Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS will be completely phased out by mid-2025. To see alternatives please check here

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