Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit 3579ba08 authored by Markus Quaritsch's avatar Markus Quaritsch
Browse files

started working on EPTP powertrain creation

parent 9f00a20b
No related branches found
No related tags found
No related merge requests found
Showing with 602 additions and 384 deletions
......@@ -24,6 +24,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AMT/@EntryIndexedValue">AMT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AT/@EntryIndexedValue">AT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CSV/@EntryIndexedValue">CSV</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EPTP/@EntryIndexedValue">EPTP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HVAC/@EntryIndexedValue">HVAC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JSON/@EntryIndexedValue">JSON</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MT/@EntryIndexedValue">MT</s:String>
......
......@@ -74,6 +74,9 @@ namespace TUGraz.VectoCore.InputData.Reader
if (DistanceBasedCycleDataParser.ValidateHeader(cols, false)) {
return CycleType.DistanceBased;
}
if (EPTPCycleDataParser.ValidateHeader(cols, false)) {
return CycleType.EPTP;
}
throw new VectoException("CycleFile format is unknown.");
}
......@@ -92,7 +95,10 @@ namespace TUGraz.VectoCore.InputData.Reader
return new MeasuredSpeedDataParser();
case CycleType.PTO:
return new PTOCycleDataParser();
default:
case CycleType.EPTP:
return new EPTPCycleDataParser();
default:
throw new ArgumentOutOfRangeException("Cycle Type", type.ToString());
}
}
......@@ -311,6 +317,8 @@ namespace TUGraz.VectoCore.InputData.Reader
public const string RoadGradient = "grad";
public const string StoppingTime = "stop";
public const string EngineSpeed = "n";
public const string EngineSpeedSuffix = "n_eng";
public const string FanSpeed = "n_fan";
public const string Gear = "gear";
public const string AdditionalAuxPowerDemand = "Padd";
public const string AirSpeedRelativeToVehicle = "vair_res";
......@@ -698,7 +706,56 @@ namespace TUGraz.VectoCore.InputData.Reader
return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux);
}
}
}
/// <summary>
/// Parser for PTO Cycles.
/// </summary>
// <t>,<v> [km/h],<Pwheel> [kW],<n_eng> [rpm],<n_fan> [rpm], <Padd> [kW]
private class EPTPCycleDataParser : AbstractCycleDataParser
{
public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired)
{
ValidateHeader(table.Columns);
var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry {
Time = row.ParseDouble(Fields.Time).SI<Second>(),
VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(),
AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.Cast<Watt>(),
PWheel = row.ParseDouble(Fields.PWheel).SI().Kilo.Watt.Cast<Watt>(),
EngineSpeed = row.ParseDouble(Fields.EngineSpeedSuffix).RPMtoRad(),
FanSpeed = row.ParseDouble(Fields.FanSpeed).RPMtoRad()
}).ToArray();
return entries;
}
public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true)
{
var requiredCols = new[] {
Fields.Time,
Fields.VehicleSpeed,
Fields.PWheel,
Fields.EngineSpeedSuffix,
Fields.FanSpeed
};
var allowedCols = new[] {
Fields.Time,
Fields.VehicleSpeed,
Fields.AdditionalAuxPowerDemand,
Fields.PWheel,
Fields.EngineSpeedSuffix,
Fields.FanSpeed
};
const bool allowAux = true;
return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) &&
CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions);
}
}
}
#endregion
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using TUGraz.VectoCommon.InputData;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.Configuration;
using TUGraz.VectoCore.InputData.Reader.ComponentData;
using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter;
using TUGraz.VectoCore.Models.Declaration;
using TUGraz.VectoCore.Models.Simulation.Data;
namespace TUGraz.VectoCore.InputData.Reader.Impl {
internal class EngineeringEPTPModeVectoRunDataFactory : IVectoRunDataFactory
{
protected IEPTPInputDataProvider InputDataProvider;
public EngineeringEPTPModeVectoRunDataFactory(IEPTPInputDataProvider eptpProvider)
{
InputDataProvider = eptpProvider;
}
public IEnumerable<VectoRunData> NextRun()
{
var dao = new DeclarationDataAdapter();
var segment = DeclarationData.Segments.Lookup(InputDataProvider.JobInputData.Vehicle.VehicleCategory,
InputDataProvider.JobInputData.Vehicle.AxleConfiguration,
InputDataProvider.JobInputData.Vehicle.GrossVehicleMassRating,
InputDataProvider.JobInputData.Vehicle.CurbMassChassis);
var driverdata = dao.CreateDriverData();
driverdata.AccelerationCurve = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile);
var tempVehicle = dao.CreateVehicleData(InputDataProvider.JobInputData.Vehicle, segment.Missions.First(),
segment.Missions.First().Loadings.First().Value, segment.MunicipalBodyWeight);
var airdragData = dao.CreateAirdragData(InputDataProvider.JobInputData.Vehicle.AirdragInputData,
segment.Missions.First(), segment);
var engineData = dao.CreateEngineData(InputDataProvider.JobInputData.Vehicle.EngineInputData,
InputDataProvider.JobInputData.Vehicle.EngineIdleSpeed,
InputDataProvider.JobInputData.Vehicle.GearboxInputData, InputDataProvider.JobInputData.Vehicle.TorqueLimits);
var axlegearData = dao.CreateAxleGearData(InputDataProvider.JobInputData.Vehicle.AxleGearInputData, false);
var angledriveData = dao.CreateAngledriveData(InputDataProvider.JobInputData.Vehicle.AngledriveInputData, false);
var gearboxData = dao.CreateGearboxData(InputDataProvider.JobInputData.Vehicle.GearboxInputData, engineData,
axlegearData.AxleGear.Ratio,
tempVehicle.DynamicTyreRadius, tempVehicle.VehicleCategory, false);
var retarderData = dao.CreateRetarderData(InputDataProvider.JobInputData.Vehicle.RetarderInputData);
var ptoTransmissionData = dao.CreatePTOTransmissionData(InputDataProvider.JobInputData.Vehicle.PTOTransmissionInputData);
var aux = dao.CreateAuxiliaryData(InputDataProvider.JobInputData.Vehicle.AuxiliaryInputData(), MissionType.RegionalDelivery, segment.VehicleClass).ToList();
aux.RemoveAll(x => x.ID == Constants.Auxiliaries.IDs.Fan);
aux.Add(new VectoRunData.AuxData {
DemandType = AuxiliaryDemandType.Direct,
ID = DrivingCycleDataReader.Fields.AdditionalAuxPowerDemand
});
return InputDataProvider.JobInputData.Cycles.Select(cycle => {
var drivingCycle = DrivingCycleDataReader.ReadFromDataTable(cycle.CycleData, cycle.Name, false);
return new VectoRunData {
JobName = InputDataProvider.JobInputData.Vehicle.VIN,
EngineData = engineData,
GearboxData = gearboxData,
AxleGearData = axlegearData,
AngledriveData = angledriveData,
VehicleData = dao.CreateVehicleData(InputDataProvider.JobInputData.Vehicle, segment.Missions.First(),
0.SI<Kilogram>(), segment.MunicipalBodyWeight),
AirdragData =airdragData,
DriverData = null,
Aux = aux,
AdvancedAux = null,
Retarder = dao.CreateRetarderData(InputDataProvider.JobInputData.Vehicle.RetarderInputData),
PTO = ptoTransmissionData,
Cycle = new DrivingCycleProxy(drivingCycle, cycle.Name),
ExecutionMode = ExecutionMode.Engineering
};
});
}
}
}
\ No newline at end of file
......@@ -33,6 +33,7 @@ using System;
using System.Linq;
using TUGraz.VectoCommon.Exceptions;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.Configuration;
using TUGraz.VectoCore.Models.Declaration;
using TUGraz.VectoCore.Models.Simulation.Data;
......@@ -69,6 +70,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
return BuildEngineOnly(data);
case CycleType.PWheel:
return BuildPWheel(data);
case CycleType.EPTP:
return BuildEPTP(data);
case CycleType.MeasuredSpeed:
return BuildMeasuredSpeed(data);
case CycleType.MeasuredSpeedGear:
......@@ -124,7 +127,40 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
return container;
}
private VehicleContainer BuildMeasuredSpeed(VectoRunData data)
private VehicleContainer BuildEPTP(VectoRunData data)
{
if (data.Cycle.CycleType != CycleType.PWheel) {
throw new VectoException("CycleType must be PWheel.");
}
var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data };
var gearbox = new CycleGearbox(container, data);
// PWheelCycle --> AxleGear --> Clutch --> Engine <-- Aux
var powertrain = new EPTPCycle(container, data.Cycle, data.AxleGearData.AxleGear.Ratio, data.VehicleData,
gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio))
.AddComponent(new AxleGear(container, data.AxleGearData))
.AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null)
.AddComponent(gearbox, data.Retarder, container)
.AddComponent(new Clutch(container, data.EngineData));
var engine = new CombustionEngine(container, data.EngineData, pt1Disabled: true);
var aux = CreateAuxiliaries(data, container);
aux.AddCycle(Constants.Auxiliaries.IDs.Fan, cycleEntry => {
var fanSpeed = cycleEntry.FanSpeed.AsRPM;
return (c1 * Math.Pow(fanSpeed / c2, 3) * Math.Pow(fanSpeed / c3, 5)*1000).SI<Watt>();
});
engine.Connect(aux.Port());
var idleController = GetIdleController(data.PTO, engine, container);
powertrain.AddComponent(engine, idleController);
//.AddAuxiliaries(container, data);
return container;
}
private VehicleContainer BuildMeasuredSpeed(VectoRunData data)
{
if (data.Cycle.CycleType != CycleType.MeasuredSpeed) {
throw new VectoException("CycleType must be MeasuredSpeed.");
......@@ -272,7 +308,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
container.ModalData.AddAuxiliary(Constants.Auxiliaries.IDs.PTOConsumer,
Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOConsumer);
}
return aux;
}
......
......@@ -89,14 +89,23 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
private void CreateEngineeringDataReader(IInputDataProvider dataProvider)
{
var engDataProvider = ToEngineeringInputDataProvider(dataProvider);
if (engDataProvider.JobInputData.EngineOnlyMode) {
DataReader = new EngineOnlyVectoRunDataFactory(engDataProvider);
_engineOnlyMode = true;
} else {
DataReader = new EngineeringModeVectoRunDataFactory(engDataProvider);
}
}
if (dataProvider is IEPTPInputDataProvider) {
var eptpProvider = dataProvider as IEPTPInputDataProvider;
DataReader = new EngineeringEPTPModeVectoRunDataFactory(eptpProvider);
return;
}
if (dataProvider is IEngineeringInputDataProvider) {
var engDataProvider = dataProvider as IEngineeringInputDataProvider;
if (engDataProvider.JobInputData.EngineOnlyMode) {
DataReader = new EngineOnlyVectoRunDataFactory(engDataProvider);
_engineOnlyMode = true;
} else {
DataReader = new EngineeringModeVectoRunDataFactory(engDataProvider);
}
return;
}
throw new VectoException("Unknown InputData for Engineering Mode!");
}
private static IDeclarationInputDataProvider ToDeclarationInputDataProvider(IInputDataProvider dataProvider)
{
......@@ -107,15 +116,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
return declDataProvider;
}
private static IEngineeringInputDataProvider ToEngineeringInputDataProvider(IInputDataProvider dataProvider)
{
var engDataProvider = dataProvider as IEngineeringInputDataProvider;
if (engDataProvider == null) {
throw new VectoException("InputDataProvider does not implement Engineering interface");
}
return engDataProvider;
}
public bool Validate { get; set; }
public IVectoRunDataFactory DataReader { get; private set; }
......@@ -203,6 +203,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
break;
case CycleType.EngineOnly:
case CycleType.PWheel:
case CycleType.EPTP:
case CycleType.MeasuredSpeed:
case CycleType.MeasuredSpeedGear:
run = new TimeRun(builder.Build(data));
......
......@@ -29,208 +29,215 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCommon.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
{
public enum CycleType
{
EngineOnly,
DistanceBased,
PWheel,
MeasuredSpeed,
MeasuredSpeedGear,
PTO
}
public static class CycleTypeHelper
{
public static bool IsDistanceBased(this CycleType type)
{
return type == CycleType.DistanceBased;
}
}
public interface IDrivingCycleData
{
List<DrivingCycleData.DrivingCycleEntry> Entries { get; }
string Name { get; }
CycleType CycleType { get; }
void Finish();
}
[CustomValidation(typeof(DrivingCycleData), "ValidateCycleData")]
public class DrivingCycleData : SimulationComponentData, IDrivingCycleData
{
internal DrivingCycleData() {}
public List<DrivingCycleEntry> Entries { get; internal set; }
public string Name { get; internal set; }
public CycleType CycleType { get; internal set; }
public void Finish() {}
// ReSharper disable once UnusedMember.Global -- used by Validation
public static ValidationResult ValidateCycleData(DrivingCycleData cycleData, ValidationContext validationContext)
{
var mode = GetExecutionMode(validationContext);
if (mode == ExecutionMode.Declaration) {
return ValidationResult.Success;
}
var result = new List<string>();
if (cycleData.CycleType.IsDistanceBased()) {
var cur = cycleData.Entries[0].Distance;
for (var i = 1; i < cycleData.Entries.Count; i++) {
if (cycleData.Entries[i].Distance < cur) {
result.Add(
string.Format("distance-based cycle is not increasing strictly monotonous. entry: {0}, s_{1}: {2} s_{0}: {3}", i,
i - 1, cycleData.Entries[i - 1].Distance, cycleData.Entries[i].Distance));
}
cur = cycleData.Entries[i].Distance;
}
} else {
var cur = cycleData.Entries[0].Time;
for (var i = 1; i < cycleData.Entries.Count; i++) {
if (cycleData.Entries[i].Time < cur) {
result.Add(
string.Format("time-based cycle is not increasing strictly monotonous. entry: {0}, t_{1}: {2} t_{0}: {3}", i,
i - 1, cycleData.Entries[i - 1].Time, cycleData.Entries[i].Time));
}
cur = cycleData.Entries[i].Time;
}
}
if (result.Any()) {
return new ValidationResult(string.Format("Validation of Cycle {0} failed", cycleData.Name), result);
}
return ValidationResult.Success;
}
[DebuggerDisplay(
"s:{Distance}, t:{Time}, v:{VehicleTargetSpeed}, grad:{RoadGradient}, n:{AngularVelocity}, gear:{Gear}")]
public class DrivingCycleEntry
{
public DrivingCycleEntry() {}
public DrivingCycleEntry(DrivingCycleEntry entry)
{
Distance = entry.Distance;
Time = entry.Time;
VehicleTargetSpeed = entry.VehicleTargetSpeed;
RoadGradient = entry.RoadGradient;
Altitude = entry.Altitude;
StoppingTime = entry.StoppingTime;
AngularVelocity = entry.AngularVelocity;
Gear = entry.Gear;
AdditionalAuxPowerDemand = entry.AdditionalAuxPowerDemand;
AirSpeedRelativeToVehicle = entry.AirSpeedRelativeToVehicle;
WindYawAngle = entry.WindYawAngle;
Torque = entry.Torque;
Drag = entry.Drag;
PTOActive = entry.PTOActive;
AuxiliarySupplyPower = new Dictionary<string, Watt>(entry.AuxiliarySupplyPower);
}
/// <summary>
/// Travelled distance used for distance-based cycles. If "t" is also defined this column will be ignored.
/// </summary>
public Meter Distance;
/// <summary>
/// Used for time-based cycles. If neither this nor the distance. "s" is defined the data will be interpreted as 1Hz.
/// </summary>
public Second Time;
/// <summary>
/// Required except for Engine Only Mode calculations.
/// </summary>
public MeterPerSecond VehicleTargetSpeed;
/// <summary>
/// Optional.
/// </summary>
public Radian RoadGradient;
/// <summary>
/// [%] Optional.
/// </summary>
public Scalar RoadGradientPercent
{
get { return (Math.Tan(RoadGradient.Value()) * 100).SI<Scalar>(); }
}
/// <summary>
/// relative altitude of the driving cycle over distance
/// </summary>
public Meter Altitude;
/// <summary>
/// Required for distance-based cycles. Not used in time based cycles. "stop" defines the time the vehicle spends in stop phases.
/// </summary>
public Second StoppingTime;
/// <summary>
/// Supply Power input for each auxiliary defined in the .vecto file where xxx matches the ID of the corresponding
/// Auxiliary. ID's are not case sensitive and must not contain space or special characters.
/// </summary>
public Dictionary<string, Watt> AuxiliarySupplyPower;
/// <summary>
/// If "n_eng_avg" is defined VECTO uses that instead of the calculated engine speed value.
/// </summary>
public PerSecond AngularVelocity;
/// <summary>
/// [-] Gear input. Overwrites the gear shift model.
/// </summary>
public uint Gear;
/// <summary>
/// This power input will be directly added to the engine power in addition to possible other auxiliaries. Also used in Engine Only Mode.
/// </summary>
public Watt AdditionalAuxPowerDemand;
/// <summary>
/// Only required if Cross Wind Correction is set to Vair and Beta Input.
/// </summary>
public MeterPerSecond AirSpeedRelativeToVehicle;
/// <summary>
/// [°] Only required if Cross Wind Correction is set to Vair and Beta Input.
/// </summary>
public double WindYawAngle;
/// <summary>
/// Effective engine torque at clutch. Only required in Engine Only Mode. Alternatively power "Pe" can be defined. Use "DRAG" to define motoring operation.
/// </summary>
public NewtonMeter Torque;
public bool Drag;
/// <summary>
/// Power on the Wheels (only used in PWheel Mode).
/// </summary>
public Watt PWheel;
public bool? TorqueConverterActive { get; set; }
/// <summary>
/// The angular velocity at the wheel. only used in PWheelCycle.
/// </summary>
public PerSecond WheelAngularVelocity;
/// <summary>
/// Flag if PTO Cycle is active or not.
/// </summary>
public bool PTOActive;
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCommon.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
{
public enum CycleType
{
EngineOnly,
DistanceBased,
PWheel,
MeasuredSpeed,
MeasuredSpeedGear,
PTO,
EPTP
}
public static class CycleTypeHelper
{
public static bool IsDistanceBased(this CycleType type)
{
return type == CycleType.DistanceBased;
}
}
public interface IDrivingCycleData
{
List<DrivingCycleData.DrivingCycleEntry> Entries { get; }
string Name { get; }
CycleType CycleType { get; }
void Finish();
}
[CustomValidation(typeof(DrivingCycleData), "ValidateCycleData")]
public class DrivingCycleData : SimulationComponentData, IDrivingCycleData
{
internal DrivingCycleData() {}
public List<DrivingCycleEntry> Entries { get; internal set; }
public string Name { get; internal set; }
public CycleType CycleType { get; internal set; }
public void Finish() {}
// ReSharper disable once UnusedMember.Global -- used by Validation
public static ValidationResult ValidateCycleData(DrivingCycleData cycleData, ValidationContext validationContext)
{
var mode = GetExecutionMode(validationContext);
if (mode == ExecutionMode.Declaration) {
return ValidationResult.Success;
}
var result = new List<string>();
if (cycleData.CycleType.IsDistanceBased()) {
var cur = cycleData.Entries[0].Distance;
for (var i = 1; i < cycleData.Entries.Count; i++) {
if (cycleData.Entries[i].Distance < cur) {
result.Add(
string.Format("distance-based cycle is not increasing strictly monotonous. entry: {0}, s_{1}: {2} s_{0}: {3}", i,
i - 1, cycleData.Entries[i - 1].Distance, cycleData.Entries[i].Distance));
}
cur = cycleData.Entries[i].Distance;
}
} else {
var cur = cycleData.Entries[0].Time;
for (var i = 1; i < cycleData.Entries.Count; i++) {
if (cycleData.Entries[i].Time < cur) {
result.Add(
string.Format("time-based cycle is not increasing strictly monotonous. entry: {0}, t_{1}: {2} t_{0}: {3}", i,
i - 1, cycleData.Entries[i - 1].Time, cycleData.Entries[i].Time));
}
cur = cycleData.Entries[i].Time;
}
}
if (result.Any()) {
return new ValidationResult(string.Format("Validation of Cycle {0} failed", cycleData.Name), result);
}
return ValidationResult.Success;
}
[DebuggerDisplay(
"s:{Distance}, t:{Time}, v:{VehicleTargetSpeed}, grad:{RoadGradient}, n:{AngularVelocity}, gear:{Gear}")]
public class DrivingCycleEntry
{
public DrivingCycleEntry() {}
public DrivingCycleEntry(DrivingCycleEntry entry)
{
Distance = entry.Distance;
Time = entry.Time;
VehicleTargetSpeed = entry.VehicleTargetSpeed;
RoadGradient = entry.RoadGradient;
Altitude = entry.Altitude;
StoppingTime = entry.StoppingTime;
AngularVelocity = entry.AngularVelocity;
Gear = entry.Gear;
AdditionalAuxPowerDemand = entry.AdditionalAuxPowerDemand;
AirSpeedRelativeToVehicle = entry.AirSpeedRelativeToVehicle;
WindYawAngle = entry.WindYawAngle;
Torque = entry.Torque;
Drag = entry.Drag;
PTOActive = entry.PTOActive;
AuxiliarySupplyPower = new Dictionary<string, Watt>(entry.AuxiliarySupplyPower);
EngineSpeed = entry.EngineSpeed;
FanSpeed = entry.FanSpeed;
}
/// <summary>
/// Travelled distance used for distance-based cycles. If "t" is also defined this column will be ignored.
/// </summary>
public Meter Distance;
/// <summary>
/// Used for time-based cycles. If neither this nor the distance. "s" is defined the data will be interpreted as 1Hz.
/// </summary>
public Second Time;
/// <summary>
/// Required except for Engine Only Mode calculations.
/// </summary>
public MeterPerSecond VehicleTargetSpeed;
/// <summary>
/// Optional.
/// </summary>
public Radian RoadGradient;
/// <summary>
/// [%] Optional.
/// </summary>
public Scalar RoadGradientPercent
{
get { return (Math.Tan(RoadGradient.Value()) * 100).SI<Scalar>(); }
}
/// <summary>
/// relative altitude of the driving cycle over distance
/// </summary>
public Meter Altitude;
/// <summary>
/// Required for distance-based cycles. Not used in time based cycles. "stop" defines the time the vehicle spends in stop phases.
/// </summary>
public Second StoppingTime;
/// <summary>
/// Supply Power input for each auxiliary defined in the .vecto file where xxx matches the ID of the corresponding
/// Auxiliary. ID's are not case sensitive and must not contain space or special characters.
/// </summary>
public Dictionary<string, Watt> AuxiliarySupplyPower;
/// <summary>
/// If "n_eng_avg" is defined VECTO uses that instead of the calculated engine speed value.
/// </summary>
public PerSecond AngularVelocity;
/// <summary>
/// [-] Gear input. Overwrites the gear shift model.
/// </summary>
public uint Gear;
/// <summary>
/// This power input will be directly added to the engine power in addition to possible other auxiliaries. Also used in Engine Only Mode.
/// </summary>
public Watt AdditionalAuxPowerDemand;
/// <summary>
/// Only required if Cross Wind Correction is set to Vair and Beta Input.
/// </summary>
public MeterPerSecond AirSpeedRelativeToVehicle;
/// <summary>
/// [°] Only required if Cross Wind Correction is set to Vair and Beta Input.
/// </summary>
public double WindYawAngle;
/// <summary>
/// Effective engine torque at clutch. Only required in Engine Only Mode. Alternatively power "Pe" can be defined. Use "DRAG" to define motoring operation.
/// </summary>
public NewtonMeter Torque;
public bool Drag;
/// <summary>
/// Power on the Wheels (only used in PWheel Mode).
/// </summary>
public Watt PWheel;
public bool? TorqueConverterActive;
/// <summary>
/// The angular velocity at the wheel. only used in PWheelCycle.
/// </summary>
public PerSecond WheelAngularVelocity;
/// <summary>
/// Flag if PTO Cycle is active or not.
/// </summary>
public bool PTOActive;
public PerSecond EngineSpeed;
public PerSecond FanSpeed;
}
}
}
\ No newline at end of file
......@@ -29,163 +29,163 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using System;
using System.Collections.Generic;
using TUGraz.VectoCommon.Exceptions;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.Configuration;
using TUGraz.VectoCore.Models.Simulation;
using TUGraz.VectoCore.Models.Simulation.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
using TUGraz.VectoCore.OutputData;
namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
{
/// <summary>
/// Container Class for Auxiliaries which are connected to the Engine.
/// </summary>
public class EngineAuxiliary : StatefulVectoSimulationComponent<EngineAuxiliary.State>, IAuxInProvider,
IAuxPort
{
protected readonly Dictionary<string, Func<PerSecond, Watt>> Auxiliaries =
new Dictionary<string, Func<PerSecond, Watt>>();
public EngineAuxiliary(IVehicleContainer container) : base(container) {}
public IAuxPort Port()
{
return this;
}
/// <summary>
/// Adds a constant power demand auxiliary.
/// </summary>
/// <param name="auxId"></param>
/// <param name="powerDemand"></param>
public void AddConstant(string auxId, Watt powerDemand)
{
Add(auxId, _ => powerDemand);
}
/// <summary>
/// Adds an auxiliary which gets its power demand from the driving cycle.
/// </summary>
/// <param name="auxId"></param>
public void AddCycle(string auxId)
{
Add(auxId, _ => DataBus.CycleData.LeftSample.AdditionalAuxPowerDemand);
}
/// <summary>
/// Adds an auxiliary which calculates the demand based on a aux-map and the engine speed.
/// </summary>
/// <param name="auxId"></param>
/// <param name="data"></param>
public void AddMapping(string auxId, AuxiliaryData data)
{
if (!DataBus.CycleData.LeftSample.AuxiliarySupplyPower.ContainsKey(auxId)) {
var error = string.Format("driving cycle does not contain column for auxiliary: {0}",
Constants.Auxiliaries.Prefix + auxId);
Log.Error(error);
throw new VectoException(error);
}
Add(auxId, speed => {
var powerSupply = DataBus.CycleData.LeftSample.AuxiliarySupplyPower[auxId];
var nAuxiliary = speed * data.TransmissionRatio;
var powerAuxOut = powerSupply / data.EfficiencyToSupply;
var powerAuxIn = data.GetPowerDemand(nAuxiliary, powerAuxOut);
return powerAuxIn / data.EfficiencyToEngine;
});
}
/// <summary>
/// Adds an auxiliary with a function returning the power demand based on the engine speed.
/// </summary>
/// <param name="auxId"></param>
/// <param name="powerLossFunction"></param>
public void Add(string auxId, Func<PerSecond, Watt> powerLossFunction)
{
Auxiliaries[auxId] = powerLossFunction;
}
public NewtonMeter Initialize(NewtonMeter torque, PerSecond angularSpeed)
{
PreviousState.AngularSpeed = angularSpeed;
if (angularSpeed.IsEqual(0)) {
return 0.SI<NewtonMeter>();
}
return ComputePowerDemand(angularSpeed, false) / angularSpeed;
}
/// <summary>
/// Calculates the torque demand for all registered auxiliaries for the the current engine
/// </summary>
/// <param name="absTime"></param>
/// <param name="dt"></param>
/// <param name="torquePowerTrain"></param>
/// <param name="torqueEngine"></param>
/// <param name="angularSpeed"></param>
/// <param name="dryRun"></param>
/// <returns></returns>
public NewtonMeter TorqueDemand(Second absTime, Second dt, NewtonMeter torquePowerTrain, NewtonMeter torqueEngine,
PerSecond angularSpeed, bool dryRun = false)
{
var avgAngularSpeed = PreviousState.AngularSpeed != null
? (angularSpeed + PreviousState.AngularSpeed) / 2.0
: angularSpeed;
if (!dryRun) {
CurrentState.AngularSpeed = angularSpeed;
}
if (avgAngularSpeed.IsGreater(0)) {
return ComputePowerDemand(avgAngularSpeed, dryRun) / avgAngularSpeed;
}
return 0.SI<NewtonMeter>();
}
protected Watt ComputePowerDemand(PerSecond engineSpeed, bool dryRun)
{
var powerDemands = new Dictionary<string, Watt>(Auxiliaries.Count);
foreach (var item in Auxiliaries) {
var value = item.Value(engineSpeed);
if (value != null) {
powerDemands[item.Key] = value;
}
}
if (!dryRun) {
CurrentState.PowerDemands = powerDemands;
}
return powerDemands.Sum(kv => kv.Value);
}
protected override void DoWriteModalResults(IModalDataContainer container)
{
var auxPowerDemand = 0.SI<Watt>();
if (CurrentState.PowerDemands != null) {
foreach (var kv in CurrentState.PowerDemands) {
container[kv.Key] = kv.Value;
// mk 2016-10-11: pto's should not be counted in sum auxiliary power demand
if (kv.Key != Constants.Auxiliaries.IDs.PTOTransmission && kv.Key != Constants.Auxiliaries.IDs.PTOConsumer) {
auxPowerDemand += kv.Value;
}
}
}
if (container[ModalResultField.P_aux] == null || container[ModalResultField.P_aux] == DBNull.Value) {
// only overwrite if nobody else already wrote the total aux power
container[ModalResultField.P_aux] = auxPowerDemand;
}
}
protected override void DoCommitSimulationStep()
{
AdvanceState();
}
public class State
{
public PerSecond AngularSpeed;
public Dictionary<string, Watt> PowerDemands;
}
}
using System;
using System.Collections.Generic;
using TUGraz.VectoCommon.Exceptions;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.Configuration;
using TUGraz.VectoCore.Models.Simulation;
using TUGraz.VectoCore.Models.Simulation.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
using TUGraz.VectoCore.OutputData;
namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
{
/// <summary>
/// Container Class for Auxiliaries which are connected to the Engine.
/// </summary>
public class EngineAuxiliary : StatefulVectoSimulationComponent<EngineAuxiliary.State>, IAuxInProvider,
IAuxPort
{
protected readonly Dictionary<string, Func<PerSecond, Watt>> Auxiliaries =
new Dictionary<string, Func<PerSecond, Watt>>();
public EngineAuxiliary(IVehicleContainer container) : base(container) {}
public IAuxPort Port()
{
return this;
}
/// <summary>
/// Adds a constant power demand auxiliary.
/// </summary>
/// <param name="auxId"></param>
/// <param name="powerDemand"></param>
public void AddConstant(string auxId, Watt powerDemand)
{
Add(auxId, _ => powerDemand);
}
/// <summary>
/// Adds an auxiliary which gets its power demand from the driving cycle.
/// </summary>
/// <param name="auxId"></param>
public void AddCycle(string auxId)
{
Add(auxId, _ => DataBus.CycleData.LeftSample.AdditionalAuxPowerDemand);
}
/// <summary>
/// Adds an auxiliary which calculates the demand based on a aux-map and the engine speed.
/// </summary>
/// <param name="auxId"></param>
/// <param name="data"></param>
public void AddMapping(string auxId, AuxiliaryData data)
{
if (!DataBus.CycleData.LeftSample.AuxiliarySupplyPower.ContainsKey(auxId)) {
var error = string.Format("driving cycle does not contain column for auxiliary: {0}",
Constants.Auxiliaries.Prefix + auxId);
Log.Error(error);
throw new VectoException(error);
}
Add(auxId, speed => {
var powerSupply = DataBus.CycleData.LeftSample.AuxiliarySupplyPower[auxId];
var nAuxiliary = speed * data.TransmissionRatio;
var powerAuxOut = powerSupply / data.EfficiencyToSupply;
var powerAuxIn = data.GetPowerDemand(nAuxiliary, powerAuxOut);
return powerAuxIn / data.EfficiencyToEngine;
});
}
/// <summary>
/// Adds an auxiliary with a function returning the power demand based on the engine speed.
/// </summary>
/// <param name="auxId"></param>
/// <param name="powerLossFunction"></param>
public void Add(string auxId, Func<PerSecond, Watt> powerLossFunction)
{
Auxiliaries[auxId] = powerLossFunction;
}
public NewtonMeter Initialize(NewtonMeter torque, PerSecond angularSpeed)
{
PreviousState.AngularSpeed = angularSpeed;
if (angularSpeed.IsEqual(0)) {
return 0.SI<NewtonMeter>();
}
return ComputePowerDemand(angularSpeed, false) / angularSpeed;
}
/// <summary>
/// Calculates the torque demand for all registered auxiliaries for the the current engine
/// </summary>
/// <param name="absTime"></param>
/// <param name="dt"></param>
/// <param name="torquePowerTrain"></param>
/// <param name="torqueEngine"></param>
/// <param name="angularSpeed"></param>
/// <param name="dryRun"></param>
/// <returns></returns>
public NewtonMeter TorqueDemand(Second absTime, Second dt, NewtonMeter torquePowerTrain, NewtonMeter torqueEngine,
PerSecond angularSpeed, bool dryRun = false)
{
var avgAngularSpeed = PreviousState.AngularSpeed != null
? (angularSpeed + PreviousState.AngularSpeed) / 2.0
: angularSpeed;
if (!dryRun) {
CurrentState.AngularSpeed = angularSpeed;
}
if (avgAngularSpeed.IsGreater(0)) {
return ComputePowerDemand(avgAngularSpeed, dryRun) / avgAngularSpeed;
}
return 0.SI<NewtonMeter>();
}
protected Watt ComputePowerDemand(PerSecond engineSpeed, bool dryRun)
{
var powerDemands = new Dictionary<string, Watt>(Auxiliaries.Count);
foreach (var item in Auxiliaries) {
var value = item.Value(engineSpeed);
if (value != null) {
powerDemands[item.Key] = value;
}
}
if (!dryRun) {
CurrentState.PowerDemands = powerDemands;
}
return powerDemands.Sum(kv => kv.Value);
}
protected override void DoWriteModalResults(IModalDataContainer container)
{
var auxPowerDemand = 0.SI<Watt>();
if (CurrentState.PowerDemands != null) {
foreach (var kv in CurrentState.PowerDemands) {
container[kv.Key] = kv.Value;
// mk 2016-10-11: pto's should not be counted in sum auxiliary power demand
if (kv.Key != Constants.Auxiliaries.IDs.PTOTransmission && kv.Key != Constants.Auxiliaries.IDs.PTOConsumer) {
auxPowerDemand += kv.Value;
}
}
}
if (container[ModalResultField.P_aux] == null || container[ModalResultField.P_aux] == DBNull.Value) {
// only overwrite if nobody else already wrote the total aux power
container[ModalResultField.P_aux] = auxPowerDemand;
}
}
protected override void DoCommitSimulationStep()
{
AdvanceState();
}
public class State
{
public PerSecond AngularSpeed;
public Dictionary<string, Watt> PowerDemands;
}
}
}
\ No newline at end of file
......@@ -186,6 +186,7 @@
<Compile Include="Models\SimulationComponent\Impl\TorqueConverter.cs" />
<Compile Include="Models\SimulationComponent\Impl\IdleControllerSwitcher.cs" />
<Compile Include="Models\Simulation\Data\ModalResultField.cs" />
<Compile Include="InputData\Reader\Impl\EngineeringEPTPModeVectoRunDataFactory.cs" />
<Compile Include="OutputData\ModFilter\ActualModalDataFilter.cs" />
<Compile Include="OutputData\ModFilter\ModalData1HzFilter.cs" />
<Compile Include="OutputData\XML\AbstractXMLWriter.cs" />
......
using NUnit.Framework;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCore.InputData.FileIO.JSON;
using TUGraz.VectoCore.Models.Simulation.Impl;
using TUGraz.VectoCore.OutputData;
using TUGraz.VectoCore.OutputData.FileIO;
namespace TUGraz.VectoCore.Tests.Integration.EPTP
{
[TestFixture]
public class EPTPTest
{
[TestCase()]
public void RunEPTP()
{
var jobFile = @"E:\QUAM\Workspace\VECTO_quam\EPTP\MAN_EPTP.vecto";
var fileWriter = new FileOutputWriter(jobFile);
var sumWriter = new SummaryDataContainer(fileWriter);
var jobContainer = new JobContainer(sumWriter);
var dataProvider = JSONInputDataFactory.ReadJsonJob(jobFile);
var runsFactory = new SimulatorFactory(ExecutionMode.Engineering, dataProvider, fileWriter) {
ModalResults1Hz = false,
WriteModalResults = true,
ActualModalData = false,
Validate = false,
};
jobContainer.AddRuns(runsFactory);
jobContainer.Execute();
Assert.AreEqual(true, jobContainer.AllCompleted);
}
}
}
\ No newline at end of file
......@@ -83,6 +83,7 @@
<Compile Include="Integration\CoachAdvancedAuxPowertrain.cs" />
<Compile Include="Integration\CoachPowerTrain.cs" />
<Compile Include="Integration\DriverStrategy\SimpleCycles.cs" />
<Compile Include="Integration\EPTP\EPTPTest.cs" />
<Compile Include="Integration\FuelTypesTest.cs" />
<Compile Include="Integration\FullCycleDeclarationTest.cs">
<SubType>Code</SubType>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment