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

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

Merge pull request #220 in VECTO/vecto-sim from...

Merge pull request #220 in VECTO/vecto-sim from ~EMKRISPMI/vecto-sim:bugfix/VECTO-307-modfile-p_ret_in-to-small to develop

* commit 'e00aac2c':
  updated tests for retarder to include a case for [VECTO-307]
  added AdvanceState in DoCommitSimulationStep (bugfix for VECTO-307)
  simplified retarder loss map, documented code
  removed commented lines
parents 5f10f274 e00aac2c
No related branches found
No related tags found
No related merge requests found
......@@ -40,29 +40,58 @@ using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
{
/// <summary>
/// LossMap for retarder.
/// </summary>
public class RetarderLossMap : SimulationComponentData
{
[ValidateObject] private List<RetarderLossEntry> _entries;
private PerSecond _minSpeed;
private PerSecond _maxSpeed;
/// <summary>
/// Gets the minimal defined speed of the retarder loss map.
/// </summary>
public PerSecond MinSpeed
{
get { return _minSpeed ?? (_minSpeed = _entries.Min(e => e.RetarderSpeed)); }
}
/// <summary>
/// Gets the maximal defined speed of the retarder loss map.
/// </summary>
public PerSecond MaxSpeed
{
get { return _maxSpeed ?? (_maxSpeed = _entries.Max(e => e.RetarderSpeed)); }
}
/// <summary>
/// Read the retarder loss map from a file.
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static RetarderLossMap ReadFromFile(string fileName)
{
try {
DataTable data;
data = VectoCSVFile.Read(fileName);
return Create(data);
return Create(VectoCSVFile.Read(fileName));
} catch (Exception ex) {
throw new VectoException("ERROR while loading RetarderLossMap: " + ex.Message);
}
}
/// <summary>
/// Create the retarder loss map from an appropriate datatable. (2 columns: Retarder Speed, Torque Loss)
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static RetarderLossMap Create(DataTable data)
{
if (data.Columns.Count != 2) {
throw new VectoException("RetarderLossMap Data File must consist of 2 columns.");
throw new VectoException("RetarderLossMap Data File must consist of 2 columns: Retarder Speed, Torque Loss");
}
if (data.Rows.Count < 2) {
throw new VectoException("RetarderLossMap must consist of at least two entries.");
throw new VectoException("RetarderLossMap must contain at least 2 entries.");
}
List<RetarderLossEntry> entries;
......@@ -75,55 +104,27 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
", ".Join(data.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Reverse()));
entries = CreateFromColumnIndizes(data);
}
entries.Sort((entry1, entry2) => entry1.RetarderSpeed.Value().CompareTo(entry2.RetarderSpeed.Value()));
return new RetarderLossMap { _entries = entries };
}
public NewtonMeter RetarderLoss(PerSecond angularVelocity, bool allowExtrapolation)
/// <summary>
/// Calculates the retarder losses.
/// </summary>
/// <param name="angularVelocity"></param>
/// <returns></returns>
public NewtonMeter RetarderLoss(PerSecond angularVelocity)
{
if (angularVelocity < _entries.First().RetarderSpeed) {
if (!allowExtrapolation) {
throw new VectoSimulationException("angular velocity {0} below min. entry in retarder loss map ({1})",
angularVelocity, _entries.First().RetarderSpeed);
}
Log.Warn("Extrapolating retarder losses! Angular velocity {0} below min. entry in retarder loss map ({1})",
angularVelocity, _entries.First().RetarderSpeed);
}
if (angularVelocity > _entries.Last().RetarderSpeed) {
if (!allowExtrapolation) {
throw new VectoSimulationException("angular velocity {0} above max. entry in retarder loss map ({1})",
angularVelocity, _entries.Last().RetarderSpeed);
}
Log.Warn("Extrapolating retarder losses! Angular velocity {0} above max. entry in retarder loss map ({1})",
angularVelocity, _entries.Last().RetarderSpeed);
}
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.Info("requested rpm below minimum rpm in retarder loss map - extrapolating. n_eng_avg: {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;
var s = _entries.GetSection(e => e.RetarderSpeed < angularVelocity);
return VectoMath.Interpolate(s.Item1.RetarderSpeed, s.Item2.RetarderSpeed, s.Item1.TorqueLoss, s.Item2.TorqueLoss,
angularVelocity);
}
private static List<RetarderLossEntry> CreateFromColumnNames(DataTable data)
{
return (from DataRow row in data.Rows
select new RetarderLossEntry {
return data.Rows.Cast<DataRow>()
.Select(row => new RetarderLossEntry {
RetarderSpeed = row.ParseDouble(Fields.RetarderSpeed).RPMtoRad(),
TorqueLoss = row.ParseDouble(Fields.TorqueLoss).SI<NewtonMeter>()
}).ToList();
......@@ -136,12 +137,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
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();
return data.Rows.Cast<DataRow>()
.Select(row => new RetarderLossEntry {
RetarderSpeed = row.ParseDouble(0).RPMtoRad(),
TorqueLoss = row.ParseDouble(1).SI<NewtonMeter>()
}).ToList();
}
private class RetarderLossEntry
......
......@@ -29,6 +29,7 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using TUGraz.VectoCommon.Exceptions;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.Models.Connector.Ports;
......@@ -39,15 +40,23 @@ using TUGraz.VectoCore.OutputData;
namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
{
/// <summary>
/// Retarder component.
/// </summary>
public class Retarder : StatefulVectoSimulationComponent<SimpleComponentState>, IPowerTrainComponent, ITnInPort,
ITnOutPort
{
protected ITnOutPort NextComponent;
private readonly RetarderLossMap _lossMap;
private double _ratio;
private readonly double _ratio;
public Retarder(IVehicleContainer cockpit, RetarderLossMap lossMap, double ratio) : base(cockpit)
/// <summary>
/// Creates a new Retarder.
/// </summary>
/// <param name="container"></param>
/// <param name="lossMap"></param>
/// <param name="ratio"></param>
public Retarder(IVehicleContainer container, RetarderLossMap lossMap, double ratio) : base(container)
{
_lossMap = lossMap;
_ratio = ratio;
......@@ -56,11 +65,25 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
protected override void DoWriteModalResults(IModalDataContainer container)
{
var avgAngularSpeed = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0;
container[ModalResultField.P_ret_loss] = (PreviousState.InTorque - PreviousState.OutTorque) * avgAngularSpeed;
container[ModalResultField.P_ret_loss] = (CurrentState.InTorque - CurrentState.OutTorque) * avgAngularSpeed;
container[ModalResultField.P_retarder_in] = CurrentState.InTorque * avgAngularSpeed;
}
protected override void DoCommitSimulationStep() {}
protected override void DoCommitSimulationStep()
{
var avgAngularSpeed = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0;
if (!avgAngularSpeed.IsBetween(_lossMap.MinSpeed, _lossMap.MaxSpeed)) {
Log.Warn(
"Retarder LossMap data was extrapolated: range for loss map is not sufficient: n:{0} (min:{1}, max:{2}), ratio:{3}",
CurrentState.OutAngularVelocity.AsRPM, _lossMap.MinSpeed.AsRPM, _lossMap.MaxSpeed.AsRPM, _ratio);
if (DataBus.ExecutionMode == ExecutionMode.Declaration) {
throw new VectoException(
"Retarder LossMap data was extrapolated in Declaration mode: range for loss map is not sufficient: n:{0} (min:{1}, max:{2}), ratio:{3}",
CurrentState.OutAngularVelocity.AsRPM, _lossMap.MinSpeed.AsRPM, _lossMap.MaxSpeed.AsRPM, _ratio);
}
}
AdvanceState();
}
public ITnInPort InPort()
{
......@@ -83,20 +106,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
return NextComponent.Request(absTime, dt, torque, null, dryRun);
}
var avgAngularSpeed = (PreviousState.InAngularVelocity + angularVelocity) / 2.0;
var retarderTorqueLoss =
_lossMap.RetarderLoss(avgAngularSpeed * _ratio, DataBus.ExecutionMode != ExecutionMode.Declaration) / _ratio;
var retarderTorqueLoss = _lossMap.RetarderLoss(avgAngularSpeed * _ratio) / _ratio;
CurrentState.SetState(torque + retarderTorqueLoss, angularVelocity, torque, angularVelocity);
return NextComponent.Request(absTime, dt, torque + retarderTorqueLoss, angularVelocity, dryRun);
return NextComponent.Request(absTime, dt, CurrentState.InTorque, CurrentState.InAngularVelocity, dryRun);
}
public IResponse Initialize(NewtonMeter torque, PerSecond angularVelocity)
{
var retarderTorqueLoss =
_lossMap.RetarderLoss(angularVelocity * _ratio, DataBus.ExecutionMode != ExecutionMode.Declaration) / _ratio;
var retarderTorqueLoss = _lossMap.RetarderLoss(angularVelocity * _ratio) / _ratio;
PreviousState.SetState(torque + retarderTorqueLoss, angularVelocity, torque, angularVelocity);
return NextComponent.Initialize(torque + retarderTorqueLoss, angularVelocity);
return NextComponent.Initialize(PreviousState.InTorque, PreviousState.InAngularVelocity);
}
}
}
\ No newline at end of file
......@@ -90,12 +90,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent
PreviousState = CurrentState;
CurrentState = new TStateType();
}
//protected virtual Watt GetPowerLoss(SimpleComponentState previousState, SimpleComponentState currentState)
//{
// return (previousState.InAngularVelocity + currentState.InAngularVelocity) / 2.0 *
// (currentState.InTorque - currentState.OutTorque);
//}
}
public class SimpleComponentState
......@@ -106,13 +100,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent
public PerSecond OutAngularVelocity = 0.SI<PerSecond>();
public PerSecond InAngularVelocity = 0.SI<PerSecond>();
//public NewtonMeter TorqueLoss = 0.SI<NewtonMeter>();
//public Watt PowerLoss()
//{
// return InTorque * InAngularVelocity - OutTorque * OutAngularVelocity;
//}
public void SetState(NewtonMeter inTorque, PerSecond inAngularVelocity, NewtonMeter outTorque,
PerSecond outAngularVelocity)
{
......@@ -120,8 +107,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent
InAngularVelocity = inAngularVelocity;
OutTorque = outTorque;
OutAngularVelocity = outAngularVelocity;
//TorqueLoss = (inTorque * inAngularVelocity - outTorque * outAngularVelocity) / inAngularVelocity;
}
}
}
\ No newline at end of file
......@@ -77,17 +77,25 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
Assert.AreEqual(112, nextRequest.Torque.Value(), Delta);
// --------
outPort.Initialize(50.SI<NewtonMeter>(), 1550.RPMtoRad());
outPort.Initialize(50.SI<NewtonMeter>(), 650.RPMtoRad());
outPort.Request(absTime, dt, 50.SI<NewtonMeter>(), 1550.RPMtoRad());
retarder.CommitSimulationStep(new MockModalDataContainer());
Assert.AreEqual(1550.RPMtoRad().Value(), nextRequest.AngularVelocity.Value(), Delta);
Assert.AreEqual(50 + 14.81, nextRequest.Torque.Value(), Delta);
// (650+1550)/2 = 1100 => 12.42Nm
Assert.AreEqual(50 + 12.42, nextRequest.Torque.Value(), Delta);
//VECTO-307: added an additional request after a commit
outPort.Request(absTime, dt, 50.SI<NewtonMeter>(), 450.RPMtoRad());
Assert.AreEqual(450.RPMtoRad().Value(), nextRequest.AngularVelocity.Value(), Delta);
// avg: (1550+450)/2 = 1000 rpm => 12Nm
Assert.AreEqual(50 + 12, nextRequest.Torque.Value(), Delta);
}
[TestMethod]
public void RetarderRatioTest()
{
var vehicle = new VehicleContainer(ExecutionMode.Engineering, null, null);
var vehicle = new VehicleContainer(ExecutionMode.Engineering);
var retarderData = RetarderLossMap.ReadFromFile(RetarderLossMapFile);
var retarder = new Retarder(vehicle, retarderData, 2.0);
......@@ -132,12 +140,10 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
retarder.InPort().Connect(nextRequest);
var outPort = retarder.OutPort();
var absTime = 0.SI<Second>();
var dt = 0.SI<Second>();
// --------
AssertHelper.Exception<VectoSimulationException>(() => outPort.Initialize(50.SI<NewtonMeter>(), 1550.RPMtoRad()),
"angular velocity 324.6312 [1/s] above max. entry in retarder loss map (240.8554 [1/s])");
outPort.Initialize(50.SI<NewtonMeter>(), 2550.RPMtoRad());
outPort.Request(0.SI<Second>(), 0.SI<Second>(), 50.SI<NewtonMeter>(), 2550.RPMtoRad());
AssertHelper.Exception<VectoException>(() => retarder.CommitSimulationStep(new MockModalDataContainer()),
"Retarder LossMap data was extrapolated in Declaration mode: range for loss map is not sufficient: n:2550 (min:0, max:2300), ratio:2");
}
[TestMethod]
......
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