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

Skip to content
Snippets Groups Projects
Commit feb1e8f5 authored by Markus QUARITSCH's avatar Markus QUARITSCH
Browse files

adapt creating electric motor power map:

when selecting the first grid-point of motor speeds in the power map, allow certain tolerances. apply clustering of speed entries, use distance between clusters to select min-speed grid point so that the map can be fully extended to 0 rpm.
if the min/max torque at 0 rpm are lower/higher than the min/max values at the lowest rpm grid point, add entries at 0 rpm with the original torque values and extrapolate the electric power from the last 4 entries of the respective side of the map
this is necessary to avoid extrapolations of the power map and thus simulation aborts
parent 8f539f24
No related branches found
No related tags found
No related merge requests found
...@@ -36,16 +36,19 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData { ...@@ -36,16 +36,19 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData {
} }
var entries = (from DataRow row in data.Rows select CreateEntry(row)).ToList(); var entries = (from DataRow row in data.Rows select CreateEntry(row)).ToList();
var entriesZero = GetEntriesAtZeroRpm(entries);
var speeds = entries.Select(x => x.MotorSpeed).Distinct().Where(x => x.IsGreater(0)).ToList();
var minSpeed = speeds.OrderBy(x => x).First();
var torques = entries.Where(x => x.MotorSpeed.IsEqual(minSpeed)).ToList();
var delaunayMap = new DelaunayMap("ElectricMotorEfficiencyMap Mechanical to Electric"); var delaunayMap = new DelaunayMap("ElectricMotorEfficiencyMap Mechanical to Electric");
var retVal = new EfficiencyMapNew(delaunayMap); var retVal = new EfficiencyMapNew(delaunayMap);
foreach (var entry in torques) {
delaunayMap.AddPoint(-entry.Torque.Value() * count, foreach (var entry in entriesZero.OrderBy(x => x.Torque)) {
0, retVal.GetDelaunayZValue(entry)); try {
delaunayMap.AddPoint(-entry.Torque.Value() * count,
0,
retVal.GetDelaunayZValue(entry) * count);
} catch (Exception e) {
throw new VectoException($"EfficiencyMap - Entry {entry}: {e.Message}", e);
}
} }
foreach (var entry in entries.Where(x => x.MotorSpeed.IsGreater(0)).OrderBy(x => x.MotorSpeed) foreach (var entry in entries.Where(x => x.MotorSpeed.IsGreater(0)).OrderBy(x => x.MotorSpeed)
...@@ -63,6 +66,65 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData { ...@@ -63,6 +66,65 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData {
return retVal; return retVal;
} }
private static List<EfficiencyMap.Entry> GetEntriesAtZeroRpm(List<EfficiencyMap.Entry> entries)
{
// find entries at first grid point above 0. em-speed might vary slightly,
// so apply clustering, and use distance between first clusters to select all entries at lowest speed grid point
const int numEntriesExtrapolationFitting = 4;
var speeds = new MeanShiftClustering(){ClusterCount = 100}.FindClusters(entries.Select(x => x.MotorSpeed.AsRPM).ToArray(), 10)
.Where(x => x > 0).ToList();
var lowerSpeed = speeds.First().RPMtoRad() / 2.0;
var upperSpeed = speeds.First().RPMtoRad() + (speeds[1] - speeds.First()).RPMtoRad() / 2.0;
//entries at lowest speed gridpoint
var torquesMinRpm = entries.Where(x => x.MotorSpeed.IsBetween(lowerSpeed, upperSpeed)).OrderBy(x => x.Torque).ToList();
// entries at 0 rpm grid point
var torquesZeroRpm = entries.Where(x => x.MotorSpeed.IsEqual(0)).OrderBy(x => x.Torque).ToList();
var entriesZero = new List<EfficiencyMap.Entry>();
var avgSpeed = torquesMinRpm.Average(x => x.MotorSpeed.Value()).SI<PerSecond>();
var torquesZeroMin = torquesZeroRpm.Min(x => x.Torque);
// if at 0 rpm a torque entry below the min torque at min speed is present, extrapolate to this torque
if (torquesZeroMin.IsSmaller(torquesMinRpm.Min(x => x.Torque))) {
// extrapolate entry at 0 rpm with min torque
var negTorque = torquesMinRpm.Where(x => x.Torque <= 0).OrderBy(x => x.Torque).ToList();
if (negTorque.Count < 2) {
throw new VectoException(
"Failed to generate electrip power map - at least two negative entries are required");
}
var (k, d) = VectoMath.LeastSquaresFitting(negTorque.Take(numEntriesExtrapolationFitting), x => x.Torque.Value(),
x => x.PowerElectrical.Value());
var extrapolatedPwr = (torquesZeroMin.Value() * k + d).SI<Watt>();
entriesZero.Add(new EfficiencyMap.Entry(avgSpeed, torquesZeroMin, extrapolatedPwr));
}
// copy all entries in-between
foreach (var entry in torquesMinRpm) {
entriesZero.Add(new EfficiencyMap.Entry(avgSpeed, entry.Torque, entry.PowerElectrical));
}
// if at 0 rpm a torque entry above the max torqe at min speed is present, extrapolate to this torque
var torquesZeroMax = torquesZeroRpm.Max(x => x.Torque);
if (torquesZeroMax.IsGreater(torquesMinRpm.Max(x => x.Torque))) {
// extrapolate entry at 0 rpm with max torque
var posTorque = torquesMinRpm.Where(x => x.Torque >= 0).OrderBy(x => x.Torque).Reverse().ToList();
if (posTorque.Count < 2) {
throw new VectoException(
"Failed to generate electrip power map - at least two positive entries are required");
}
var (k, d) = VectoMath.LeastSquaresFitting(posTorque.Take(numEntriesExtrapolationFitting), x => x.Torque.Value(),
x => x.PowerElectrical.Value());
var extrapolatedPwr = (torquesZeroMax.Value() * k + d).SI<Watt>();
entriesZero.Add(new EfficiencyMap.Entry(avgSpeed, torquesZeroRpm.Max(x => x.Torque), extrapolatedPwr));
}
return entriesZero;
}
private static EfficiencyMap.Entry CreateEntry(DataRow row) private static EfficiencyMap.Entry CreateEntry(DataRow row)
{ {
return new EfficiencyMap.Entry( return new EfficiencyMap.Entry(
......
...@@ -145,7 +145,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor ...@@ -145,7 +145,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor
return null; return null;
} }
if (avgSpeed.IsGreaterOrEqual(MaxSpeed)) { if (avgSpeed.IsEqual(0.RPMtoRad()) || avgSpeed.IsGreaterOrEqual(MaxSpeed)) {
return 0.SI<NewtonMeter>(); return 0.SI<NewtonMeter>();
} }
......
...@@ -60,7 +60,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data ...@@ -60,7 +60,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
public NewtonMeter EfficiencyMapLookupTorque(Volt voltage, Watt electricPower, PerSecond avgSpeed, NewtonMeter maxEmTorque) public NewtonMeter EfficiencyMapLookupTorque(Volt voltage, Watt electricPower, PerSecond avgSpeed, NewtonMeter maxEmTorque)
{ {
if (avgSpeed.IsGreaterOrEqual(MaxSpeed)) { if (avgSpeed.IsEqual(0.RPMtoRad()) || avgSpeed.IsGreaterOrEqual(MaxSpeed)) {
return 0.SI<NewtonMeter>(); return 0.SI<NewtonMeter>();
} }
var (a, b) = GetSection(voltage); var (a, b) = GetSection(voltage);
......
...@@ -200,7 +200,7 @@ namespace TUGraz.VectoCore.Tests.FileIO ...@@ -200,7 +200,7 @@ namespace TUGraz.VectoCore.Tests.FileIO
var pwrMap = ElectricMotorMapReader.Create(pwr, 2); var pwrMap = ElectricMotorMapReader.Create(pwr, 2);
Assert.AreEqual(0, pwrMap.LookupElectricPower(-0.RPMtoRad(), -800.SI<NewtonMeter>()).ElectricalPower.Value(), 1e-3); Assert.AreEqual(0, pwrMap.LookupElectricPower(-0.RPMtoRad(), -800.SI<NewtonMeter>()).ElectricalPower.Value(), 1e-3);
Assert.AreEqual(-147.2105, pwrMap.LookupElectricPower(1.RPMtoRad(), -800.SI<NewtonMeter>()).ElectricalPower.Value(), 1e-3); Assert.AreEqual(-208.04255, pwrMap.LookupElectricPower(1.RPMtoRad(), -800.SI<NewtonMeter>()).ElectricalPower.Value(), 1e-3);
Assert.AreEqual(-16412.2624, pwrMap.LookupElectricPower(120.RPMtoRad(), -800.SI<NewtonMeter>()).ElectricalPower.Value(), 1e-3); Assert.AreEqual(-16412.2624, pwrMap.LookupElectricPower(120.RPMtoRad(), -800.SI<NewtonMeter>()).ElectricalPower.Value(), 1e-3);
......
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