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

Skip to content
Snippets Groups Projects
Commit 6bc8f124 authored by Michael KRISPER's avatar Michael KRISPER
Browse files

Merge branch 'develop' into feature/VECTO-79-add-jobcontainer-or-similar

Conflicts:
	VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs
	VectoCoreTest/VectoCoreTest.csproj
parents e1641fc7 6d84b995
No related branches found
No related tags found
No related merge requests found
Showing
with 322 additions and 62 deletions
......@@ -90,9 +90,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
public NewtonMeter FullLoadStationaryTorque(PerSecond angularVelocity)
{
var idx = FindIndex(angularVelocity);
return VectoMath.Interpolate((double)_entries[idx - 1].EngineSpeed, (double)_entries[idx].EngineSpeed,
(double)_entries[idx - 1].TorqueFullLoad, (double)_entries[idx].TorqueFullLoad,
(double)angularVelocity).SI<NewtonMeter>();
return VectoMath.Interpolate(_entries[idx - 1].EngineSpeed, _entries[idx].EngineSpeed,
_entries[idx - 1].TorqueFullLoad, _entries[idx].TorqueFullLoad,
angularVelocity);
}
/// <summary>
......@@ -113,9 +113,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
public NewtonMeter DragLoadStationaryTorque(PerSecond angularVelocity)
{
var idx = FindIndex(angularVelocity);
return VectoMath.Interpolate((double)_entries[idx - 1].EngineSpeed, (double)_entries[idx].EngineSpeed,
(double)_entries[idx - 1].TorqueDrag, (double)_entries[idx].TorqueDrag,
(double)angularVelocity).SI<NewtonMeter>();
return VectoMath.Interpolate(_entries[idx - 1].EngineSpeed, _entries[idx].EngineSpeed,
_entries[idx - 1].TorqueDrag, _entries[idx].TorqueDrag,
angularVelocity);
}
/// <summary>
......@@ -132,22 +132,38 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
}
/// <summary>
/// [rad/s] => [-]
/// [rad/s] => [s]
/// </summary>
/// <param name="angularVelocity">[rad/s]</param>
/// <returns>[-]</returns>
public double PT1(PerSecond angularVelocity)
/// <returns>[s]</returns>
public Second PT1(PerSecond angularVelocity)
{
Contract.Requires(angularVelocity.HasEqualUnit(new SI().Radian.Per.Second));
Contract.Ensures(Contract.Result<SI>().HasEqualUnit(new SI()));
var idx = FindIndex(angularVelocity);
return VectoMath.Interpolate(_entries[idx - 1].EngineSpeed.Double(),
_entries[idx].EngineSpeed.Double(),
_entries[idx - 1].PT1.Double(), _entries[idx].PT1.Double(),
angularVelocity.Double());
return VectoMath.Interpolate(_entries[idx - 1].EngineSpeed, _entries[idx].EngineSpeed,
_entries[idx - 1].PT1, _entries[idx].PT1, angularVelocity);
}
/// <summary>
/// Get the engine's rated speed from the given full-load curve (i.e. engine speed with max. power)
/// </summary>
/// <returns>[1/s]</returns>
public PerSecond RatedSpeed()
{
var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>());
for (var idx = 1; idx < _entries.Count; idx++) {
var currentMax = FindMaxPower(_entries[idx - 1], _entries[idx]);
if (currentMax.Item2 > max.Item2) {
max = currentMax;
}
}
return max.Item1;
}
/// <summary>
/// [rad/s] => index. Get item index for angularVelocity.
/// </summary>
......@@ -169,6 +185,35 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
return idx;
}
private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2)
{
if (p1.EngineSpeed == p2.EngineSpeed) {
return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
}
if (p2.EngineSpeed < p1.EngineSpeed) {
var tmp = p1;
p1 = p2;
p2 = tmp;
}
// y = kx + d
var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
if (k == 0.0.SI()) {
return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
}
var engineSpeedMaxPower = (-1 * d / (2 * k)).Cast<PerSecond>();
if (engineSpeedMaxPower < p1.EngineSpeed || engineSpeedMaxPower > p2.EngineSpeed) {
if (k > 0) {
return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
}
return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
}
//return null;
var engineTorqueMaxPower = FullLoadStationaryTorque(engineSpeedMaxPower);
return new Tuple<PerSecond, Watt>(engineSpeedMaxPower,
Formulas.TorqueToPower(engineTorqueMaxPower, engineSpeedMaxPower));
}
private static class Fields
{
/// <summary>
......@@ -272,47 +317,5 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
}
#endregion
private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2)
{
if (p1.EngineSpeed == p2.EngineSpeed) {
return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
}
if (p2.EngineSpeed < p1.EngineSpeed) {
var tmp = p1;
p1 = p2;
p2 = tmp;
}
// y = kx + d
var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
if (k == 0.0.SI()) {
return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
}
var engineSpeedMaxPower = (-1 * d / (2 * k)).Cast<PerSecond>();
if (engineSpeedMaxPower < p1.EngineSpeed || engineSpeedMaxPower > p2.EngineSpeed) {
if (k > 0) {
return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
}
return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
}
//return null;
var engineTorqueMaxPower = FullLoadStationaryTorque(engineSpeedMaxPower);
return new Tuple<PerSecond, Watt>(engineSpeedMaxPower,
Formulas.TorqueToPower(engineTorqueMaxPower, engineSpeedMaxPower));
}
public PerSecond RatedSpeed()
{
var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>());
for (var idx = 1; idx < _entries.Count; idx++) {
var currentMax = FindMaxPower(_entries[idx - 1], _entries[idx]);
if (currentMax.Item2 > max.Item2) {
max = currentMax;
}
}
return max.Item1;
}
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Common.Logging;
using TUGraz.VectoCore.Exceptions;
using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine;
using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
{
public class RetarderLossMap : SimulationComponentData
{
private List<RetarderLossEntry> _entries;
public static RetarderLossMap ReadFromFile(string fileName)
{
var data = VectoCSVFile.Read(fileName);
if (data.Columns.Count != 2) {
throw new VectoException("RetarderLossMap Data File must consist of 2 columns.");
}
if (data.Rows.Count < 2) {
throw new VectoException("RetarderLossMap must consist of at leas two entries.");
}
List<RetarderLossEntry> entries;
if (HeaderIsValid(data.Columns)) {
entries = CreateFromColumnNames(data);
} else {
var log = LogManager.GetLogger<RetarderLossMap>();
log.WarnFormat(
"RetarderLossMap: Header Line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.",
Fields.RetarderSpeed, Fields.TorqueLoss,
string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Reverse()));
entries = CreateFromColumnIndizes(data);
}
return new RetarderLossMap { _entries = entries };
}
public NewtonMeter RetarderLoss(PerSecond angularVelocity)
{
var idx = FindIndex(angularVelocity);
return VectoMath.Interpolate(_entries[idx - 1].RetarderSpeed, _entries[idx].RetarderSpeed,
_entries[idx - 1].TorqueLoss, _entries[idx].TorqueLoss, angularVelocity);
}
protected int FindIndex(PerSecond angularVelocity)
{
int idx;
if (angularVelocity < _entries[0].RetarderSpeed) {
Log.InfoFormat("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);
idx = 1;
} else {
idx = _entries.FindIndex(x => x.RetarderSpeed > angularVelocity);
}
if (idx <= 0) {
idx = angularVelocity > _entries[0].RetarderSpeed ? _entries.Count - 1 : 1;
}
return idx;
}
private static List<RetarderLossEntry> CreateFromColumnNames(DataTable data)
{
return (from DataRow row in data.Rows
select new RetarderLossEntry {
RetarderSpeed = row.ParseDouble(Fields.RetarderSpeed).RPMtoRad(),
TorqueLoss = row.ParseDouble(Fields.TorqueLoss).SI<NewtonMeter>()
}).ToList();
}
private static bool HeaderIsValid(DataColumnCollection columns)
{
return columns.Contains(Fields.RetarderSpeed) && columns.Contains(Fields.TorqueLoss);
}
private static List<RetarderLossEntry> CreateFromColumnIndizes(DataTable data)
{
return (from DataRow row in data.Rows
select
new RetarderLossEntry {
RetarderSpeed = row.ParseDouble(0).RPMtoRad(),
TorqueLoss = row.ParseDouble(1).SI<NewtonMeter>()
}).ToList();
}
private class RetarderLossEntry
{
public PerSecond RetarderSpeed { get; set; }
public NewtonMeter TorqueLoss { get; set; }
}
private static class Fields
{
/// <summary>
/// [rpm]
/// </summary>
public const string RetarderSpeed = "Retarder Speed";
/// <summary>
/// [Nm]
/// </summary>
public const string TorqueLoss = "Torque Loss";
}
}
}
\ No newline at end of file
......@@ -2,5 +2,5 @@
namespace TUGraz.VectoCore.Models.SimulationComponent
{
public interface IClutch : IInShaft, IOutShaft {}
public interface IClutch : IPowerTrainComponent {}
}
\ No newline at end of file
using TUGraz.VectoCore.Models.Connector.Ports;
namespace TUGraz.VectoCore.Models.SimulationComponent
{
public interface IPowerTrainComponent : IInShaft, IOutShaft {}
}
\ No newline at end of file
......@@ -239,13 +239,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
_currentState.StationaryFullLoadPower = Formulas.TorqueToPower(_currentState.StationaryFullLoadTorque,
angularVelocity);
var pt1 = _data.GetFullLoadCurve(gear).PT1(angularVelocity);
double pt1 = _data.GetFullLoadCurve(gear).PT1(angularVelocity).Double() / dt.TotalSeconds;
var dynFullPowerCalculated = (1 / (pt1 + 1)) *
(_currentState.StationaryFullLoadPower + pt1 * _previousState.EnginePower);
_currentState.DynamicFullLoadPower = dynFullPowerCalculated < _currentState.StationaryFullLoadPower
_currentState.DynamicFullLoadPower = (dynFullPowerCalculated < _currentState.StationaryFullLoadPower)
? dynFullPowerCalculated
: _currentState.StationaryFullLoadPower;
_currentState.DynamicFullLoadTorque = Formulas.PowerToTorque(_currentState.DynamicFullLoadPower,
angularVelocity);
}
......
using System;
using TUGraz.VectoCore.Models.Connector.Ports;
using TUGraz.VectoCore.Models.Simulation;
using TUGraz.VectoCore.Models.Simulation.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
{
public class Retarder : VectoSimulationComponent, IPowerTrainComponent, ITnInPort, ITnOutPort
{
private ITnOutPort _nextComponent;
private readonly RetarderLossMap _lossMap;
private Watt _retarderLoss;
public Retarder(IVehicleContainer cockpit, RetarderLossMap lossMap) : base(cockpit)
{
_retarderLoss = 0.SI<Watt>();
_lossMap = lossMap;
}
public override void CommitSimulationStep(IModalDataWriter writer)
{
writer[ModalResultField.PlossRetarder] = _lossMap;
}
public ITnInPort InShaft()
{
return this;
}
public ITnOutPort OutShaft()
{
return this;
}
public void Connect(ITnOutPort other)
{
_nextComponent = other;
}
public IResponse Request(TimeSpan absTime, TimeSpan dt, NewtonMeter torque, PerSecond angularVelocity)
{
var retarderTorqueLoss = _lossMap.RetarderLoss(angularVelocity);
//_retarderLoss = Formulas.TorqueToPower(torqueLoss, angularVelocity);
//var requestedPower = Formulas.TorqueToPower(torque, angularVelocity);
//requestedPower += _retarderLoss;
return _nextComponent.Request(absTime, dt, torque + retarderTorqueLoss, angularVelocity);
}
}
}
\ No newline at end of file
using System;
using TUGraz.VectoCore.Exceptions;
namespace TUGraz.VectoCore.Utils
{
public static class Formulas
......@@ -21,6 +24,9 @@ namespace TUGraz.VectoCore.Utils
/// <returns>torque [Nm]</returns>
public static NewtonMeter PowerToTorque(Watt power, PerSecond angularVelocity)
{
if (Math.Abs(angularVelocity.Double()) < 1E-10) {
throw new VectoSimulationException("Can not compute Torque for 0 angular Velocity!");
}
return power / angularVelocity;
}
}
......
using System;
using Common.Logging.Factory;
using NLog.LayoutRenderers.Wrappers;
namespace TUGraz.VectoCore.Utils
{
public class VectoMath
{
public static double Interpolate(double x1, double x2, double y1, double y2, double xint)
public static T2 Interpolate<T1, T2>(T1 x1, T1 x2, T2 y1, T2 y2, T1 xint) where T1 : SI where T2 : SIBase<T2>
{
return (xint - x1) * (y2 - y1) / (x2 - x1) + y1;
return ((xint - x1) * (y2 - y1) / (x2 - x1) + y1).Cast<T2>();
}
public static SI Abs(SI si)
......
......@@ -122,10 +122,13 @@
<Compile Include="Models\SimulationComponent\Data\DrivingCycleData.cs" />
<Compile Include="Models\SimulationComponent\Data\Engine\FuelConsumptionMap.cs" />
<Compile Include="Models\SimulationComponent\Data\Engine\FullLoadCurve.cs" />
<Compile Include="Models\SimulationComponent\Data\RetarderLossMap.cs" />
<Compile Include="Models\SimulationComponent\IClutch.cs" />
<Compile Include="Models\SimulationComponent\IEngineOnlyDrivingCycle.cs" />
<Compile Include="Models\SimulationComponent\IDriverDemandDrivingCycle.cs" />
<Compile Include="Models\SimulationComponent\Impl\Clutch.cs" />
<Compile Include="Models\SimulationComponent\Impl\Retarder.cs" />
<Compile Include="Models\SimulationComponent\IPowerTrainComponent.cs" />
<Compile Include="Utils\Formulas.cs" />
<Compile Include="Utils\IntExtensionMethods.cs" />
<Compile Include="Utils\SI.cs" />
......
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TUGraz.VectoCore.Models.Simulation.Impl;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Impl;
using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
{
[TestClass]
public class RetarderTest
{
private const string RetarderLossMapFile = @"TestData\Components\Retarder.vrlm";
private const double Delta = 0.0001;
[TestMethod]
public void RetarderBasicTest()
{
var vehicle = new VehicleContainer();
var retarderData = RetarderLossMap.ReadFromFile(RetarderLossMapFile);
var retarder = new Retarder(vehicle, retarderData);
var nextRequest = new MockTnOutPort();
retarder.InShaft().Connect(nextRequest);
var outPort = retarder.OutShaft();
var absTime = TimeSpan.FromSeconds(0);
var dt = TimeSpan.FromSeconds(0);
// --------
outPort.Request(absTime, dt, 0.SI<NewtonMeter>(), 10.RPMtoRad());
Assert.AreEqual(10.RPMtoRad().Double(), (double) nextRequest.AngularVelocity, Delta);
Assert.AreEqual(10.002, (double) nextRequest.Torque, Delta);
// --------
outPort.Request(absTime, dt, 100.SI<NewtonMeter>(), 1000.RPMtoRad());
Assert.AreEqual(1000.RPMtoRad().Double(), (double) nextRequest.AngularVelocity, Delta);
Assert.AreEqual(112, (double) nextRequest.Torque, Delta);
// --------
outPort.Request(absTime, dt, 50.SI<NewtonMeter>(), 1550.RPMtoRad());
Assert.AreEqual(1550.RPMtoRad().Double(), (double) nextRequest.AngularVelocity, Delta);
Assert.AreEqual(50 + 14.81, (double) nextRequest.Torque, Delta);
}
}
}
\ No newline at end of file
Retarder Speed [rpm],Loss Torque [Nm]
0,10
100,10.02
200,10.08
300,10.18
400,10.32
500,10.5
600,10.72
700,10.98
800,11.28
900,11.62
1000,12
1100,12.42
1200,12.88
1300,13.38
1400,13.92
1500,14.5
1600,15.12
1700,15.78
1800,16.48
1900,17.22
2000,18
2100,18.82
2200,19.68
2300,20.58
......@@ -74,6 +74,7 @@
<Compile Include="Models\SimulationComponentData\FullLoadCurveTest.cs" />
<Compile Include="Models\SimulationComponent\ClutchTest.cs" />
<Compile Include="Models\SimulationComponent\CombustionEngineTest.cs" />
<Compile Include="Models\SimulationComponent\RetarderTest.cs" />
<Compile Include="Models\Simulation\DrivingCycleTests.cs" />
<Compile Include="Models\SimulationComponent\MockPorts.cs" />
<Compile Include="Models\Simulation\SimulationTests.cs" />
......@@ -120,6 +121,9 @@
<None Include="TestData\Components\FullLoadCurve insufficient entries.vfld">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData\Components\Retarder.vrlm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData\Cycles\Coach First Cycle only.vdri">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
......
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