diff --git a/VECTO.sln.DotSettings b/VECTO.sln.DotSettings index 16a678e66c187d77cdf6020db8ce6f8575cdf8f6..20c32e9f89eb92546fd549e46252160406dfe6ea 100644 --- a/VECTO.sln.DotSettings +++ b/VECTO.sln.DotSettings @@ -17,6 +17,7 @@ <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CSV/@EntryIndexedValue">CSV</s:String> + <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PT/@EntryIndexedValue">PT</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RP/@EntryIndexedValue">RP</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SI/@EntryIndexedValue">SI</s:String> <s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=2BF7A1E51991F2458D2D1F0B29CF888B/@KeyIndexDefined">True</s:Boolean> diff --git a/VectoCore/Models/Declaration/AccelerationCurve.cs b/VectoCore/Models/Declaration/AccelerationCurve.cs new file mode 100644 index 0000000000000000000000000000000000000000..5cd90094a00391fcfc902f6cce309b145efa207a --- /dev/null +++ b/VectoCore/Models/Declaration/AccelerationCurve.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public class AccelerationCurve : LookupData<MeterPerSecond, AccelerationCurve.AccelerationEntry> + { + private List<KeyValuePair<MeterPerSecond, AccelerationEntry>> _entries; + + protected override string ResourceId + { + get { return "TUGraz.VectoCore.Resources.Declaration.AccelerationFile.vacc"; } + } + + protected override void ParseData(DataTable table) + { + _entries = table.Rows.Cast<DataRow>() + .Select(r => new KeyValuePair<MeterPerSecond, AccelerationEntry>( + r.ParseDouble("v").SI().Kilo.Meter.Per.Hour.Cast<MeterPerSecond>(), + new AccelerationEntry(r.ParseDouble("acc").SI<MeterPerSquareSecond>(), + r.ParseDouble("dec").SI<MeterPerSquareSecond>()))) + .OrderBy(x => x.Key) + .ToList(); + } + + public override AccelerationEntry Lookup(MeterPerSecond key) + { + var index = 1; + if (key < _entries[0].Key) { + Log.ErrorFormat("requested rpm below minimum rpm in pt1 - extrapolating. n: {0}, rpm_min: {1}", + key.ConvertTo().Rounds.Per.Minute, _entries[0].Key.ConvertTo().Rounds.Per.Minute); + } else { + index = _entries.FindIndex(x => x.Key > key); + if (index <= 0) { + index = (key > _entries[0].Key) ? _entries.Count - 1 : 1; + } + } + + var acc = VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, _entries[index - 1].Value.Acceleration, + _entries[index].Value.Acceleration, key); + var dec = VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, _entries[index - 1].Value.Deceleration, + _entries[index].Value.Deceleration, key); + + return new AccelerationEntry(acc, dec); + } + + public class AccelerationEntry + { + public AccelerationEntry(MeterPerSquareSecond acceleration, MeterPerSquareSecond deceleration) + { + Acceleration = acceleration; + Deceleration = deceleration; + } + + public MeterPerSquareSecond Acceleration { get; set; } + public MeterPerSquareSecond Deceleration { get; set; } + } + } +} \ No newline at end of file diff --git a/VectoCore/Models/Declaration/Declaration.cs b/VectoCore/Models/Declaration/Declaration.cs index 537818cacafddf020d32461572c47e01e0bfe233..b0e6fc01d38f80c20ad4819405c95b223df6518f 100644 --- a/VectoCore/Models/Declaration/Declaration.cs +++ b/VectoCore/Models/Declaration/Declaration.cs @@ -4,7 +4,7 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.Declaration { - public class DeclarationRims : LookupData<DeclarationRims.RimsEntry, string> + public class DeclarationRims : LookupData<string, DeclarationRims.RimsEntry> { internal DeclarationRims() { diff --git a/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/Models/Declaration/DeclarationData.cs index d572591c627845ec8e03ecb08a30e03832f1169d..0c2798995532bbdf6efcd0e1100146a82a1189b2 100644 --- a/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/Models/Declaration/DeclarationData.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using TUGraz.VectoCore.Exceptions; -using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.Declaration { @@ -14,6 +9,7 @@ namespace TUGraz.VectoCore.Models.Declaration private readonly DeclarationRims _rims; private readonly DeclarationWheels _wheels; private readonly DeclarationPT1 _pt1; + private readonly AccelerationCurve _accelerationCurve; public static DeclarationWheels Wheels { @@ -35,12 +31,18 @@ namespace TUGraz.VectoCore.Models.Declaration get { return Instance()._pt1; } } + public static AccelerationCurve AccelerationCurve + { + get { return Instance()._accelerationCurve; } + } + private DeclarationData() { _wheels = new DeclarationWheels(); _rims = new DeclarationRims(); _segments = new DeclarationSegments(); _pt1 = new DeclarationPT1(); + _accelerationCurve = new AccelerationCurve(); } private static DeclarationData Instance() @@ -48,43 +50,4 @@ namespace TUGraz.VectoCore.Models.Declaration return _instance ?? (_instance = new DeclarationData()); } } - - public class DeclarationPT1 : LookupData<Second, PerSecond> - { - private List<KeyValuePair<PerSecond, Second>> _entries; - - protected override string ResourceId - { - get { return "TUGraz.VectoCore.Resources.Declaration.PT1.csv"; } - } - - protected override void ParseData(DataTable table) - { - _entries = table.Rows.Cast<DataRow>() - .Select(r => new KeyValuePair<PerSecond, Second>(r.ParseDouble("rpm").RPMtoRad(), r.ParseDouble("PT1").SI<Second>())) - .OrderBy(x => x.Key) - .ToList(); - } - - public override Second Lookup(PerSecond key) - { - var index = 1; - if (key < _entries[0].Key) { - Log.ErrorFormat("requested rpm below minimum rpm in pt1 - extrapolating. n: {0}, rpm_min: {1}", - key.ConvertTo().Rounds.Per.Minute, _entries[0].Key.ConvertTo().Rounds.Per.Minute); - } else { - index = _entries.FindIndex(x => x.Key > key); - if (index <= 0) { - index = (key > _entries[0].Key) ? _entries.Count - 1 : 1; - } - } - - var pt1 = VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, _entries[index - 1].Value, - _entries[index].Value, key); - if (pt1 < 0) { - throw new VectoException("The calculated value must not be smaller than 0. Value: " + pt1); - } - return pt1; - } - } } \ No newline at end of file diff --git a/VectoCore/Models/Declaration/DeclarationPT1.cs b/VectoCore/Models/Declaration/DeclarationPT1.cs new file mode 100644 index 0000000000000000000000000000000000000000..92e18849bc284fc73b19c3857aceebca3f7e4d7d --- /dev/null +++ b/VectoCore/Models/Declaration/DeclarationPT1.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCore.Exceptions; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public class DeclarationPT1 : LookupData<PerSecond, Second> + { + private List<KeyValuePair<PerSecond, Second>> _entries; + + protected override string ResourceId + { + get { return "TUGraz.VectoCore.Resources.Declaration.PT1.csv"; } + } + + protected override void ParseData(DataTable table) + { + _entries = table.Rows.Cast<DataRow>() + .Select(r => new KeyValuePair<PerSecond, Second>(r.ParseDouble("rpm").RPMtoRad(), r.ParseDouble("PT1").SI<Second>())) + .OrderBy(x => x.Key) + .ToList(); + } + + public override Second Lookup(PerSecond key) + { + var index = 1; + if (key < _entries[0].Key) { + Log.ErrorFormat("requested rpm below minimum rpm in pt1 - extrapolating. n: {0}, rpm_min: {1}", + key.ConvertTo().Rounds.Per.Minute, _entries[0].Key.ConvertTo().Rounds.Per.Minute); + } else { + index = _entries.FindIndex(x => x.Key > key); + if (index <= 0) { + index = (key > _entries[0].Key) ? _entries.Count - 1 : 1; + } + } + + var pt1 = VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, _entries[index - 1].Value, + _entries[index].Value, key); + if (pt1 < 0) { + throw new VectoException("The calculated value must not be smaller than 0. Value: " + pt1); + } + return pt1; + } + } +} \ No newline at end of file diff --git a/VectoCore/Models/Declaration/DeclarationWheels.cs b/VectoCore/Models/Declaration/DeclarationWheels.cs index 43f4291c161afdedb2d81674c8ddb46ed120d721..f36bb36c64efaa025c3fed26701ddc8b5c747b3b 100644 --- a/VectoCore/Models/Declaration/DeclarationWheels.cs +++ b/VectoCore/Models/Declaration/DeclarationWheels.cs @@ -5,7 +5,7 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.Declaration { - public class DeclarationWheels : LookupData<DeclarationWheels.WheelsEntry, string> + public class DeclarationWheels : LookupData<string, DeclarationWheels.WheelsEntry> { protected override string ResourceId { diff --git a/VectoCore/Models/Declaration/LookupData.cs b/VectoCore/Models/Declaration/LookupData.cs index 260da0ab3413fa3d5e44b07b97e52f2571ea8e23..2932bce3337ac2202548c5dcd34d5204348da1c0 100644 --- a/VectoCore/Models/Declaration/LookupData.cs +++ b/VectoCore/Models/Declaration/LookupData.cs @@ -7,7 +7,7 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.Declaration { - public abstract class LookupData<TEntryType, TKeyType> + public abstract class LookupData<TKeyType, TEntryType> { protected LookupData() { diff --git a/VectoCore/Resources/Declaration/AccelerationFile.vacc b/VectoCore/Resources/Declaration/AccelerationFile.vacc new file mode 100644 index 0000000000000000000000000000000000000000..54e77864874d21d67e8f8d69a97b35c5c6031749 --- /dev/null +++ b/VectoCore/Resources/Declaration/AccelerationFile.vacc @@ -0,0 +1,6 @@ +v [km/h],acc [m/s²],dec [m/s²] +0,1,-1 +25,1,-1 +50,0.642857143,-1 +60,0.5,-0.5 +120,0.5,-0.5 diff --git a/VectoCore/VectoCore.csproj b/VectoCore/VectoCore.csproj index ccfe6f136a87410320f27070e5b2d2ee6adc6570..8329b85d590e61331394d3c1969d98c63c916435 100644 --- a/VectoCore/VectoCore.csproj +++ b/VectoCore/VectoCore.csproj @@ -122,7 +122,9 @@ <Compile Include="Models\Connector\Ports\Impl\Response.cs" /> <Compile Include="Models\Connector\Ports\IFvPort.cs" /> <Compile Include="Models\Connector\Ports\ITnPort.cs" /> + <Compile Include="Models\Declaration\AccelerationCurve.cs" /> <Compile Include="Models\Declaration\DeclarationData.cs" /> + <Compile Include="Models\Declaration\DeclarationPT1.cs" /> <Compile Include="Models\Declaration\LookupData.cs" /> <Compile Include="Models\Declaration\Declaration.cs" /> <Compile Include="Models\Declaration\DeclarationWheels.cs" /> @@ -230,6 +232,7 @@ <EmbeddedResource Include="Resources\Declaration\MissionCycles\RegionalDelivery.vdri" /> <EmbeddedResource Include="Resources\Declaration\MissionCycles\UrbanDelivery.vdri" /> <EmbeddedResource Include="Resources\Declaration\PT1.csv" /> + <EmbeddedResource Include="Resources\Declaration\AccelerationFile.vacc" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. diff --git a/VectoCoreTest/Models/DeclarationDataTest.cs b/VectoCoreTest/Models/DeclarationDataTest.cs index 88d29af67436638cd8fee703e54d3625517a0a9c..d054f3d960856edfac0d4f1a70af60ff4671aa88 100644 --- a/VectoCoreTest/Models/DeclarationDataTest.cs +++ b/VectoCoreTest/Models/DeclarationDataTest.cs @@ -14,6 +14,19 @@ namespace TUGraz.VectoCore.Tests.Models { public const double Tolerance = 0.0001; + public static void AssertException<T>(Action func, string message = null) where T : Exception + { + try { + func(); + Assert.Fail("Expected an exception."); + } catch (T ex) { + if (!string.IsNullOrEmpty(message)) { + Assert.AreEqual(message, ex.Message); + } + } + } + + [TestMethod] public void WheelDataTest() { @@ -40,62 +53,73 @@ namespace TUGraz.VectoCore.Tests.Models [TestMethod] public void PT1Test() { - const double TOLERANCE = 0.0001; var pt1 = DeclarationData.PT1; // FIXED POINTS - Assert.AreEqual(0, pt1.Lookup(400.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.47, pt1.Lookup(800.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.58, pt1.Lookup(1000.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.53, pt1.Lookup(1200.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.46, pt1.Lookup(1400.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.43, pt1.Lookup(1500.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.22, pt1.Lookup(1750.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.2, pt1.Lookup(1800.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.11, pt1.Lookup(2000.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.11, pt1.Lookup(2500.RPMtoRad()).Double(), TOLERANCE); + Assert.AreEqual(0, pt1.Lookup(400.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.47, pt1.Lookup(800.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.58, pt1.Lookup(1000.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.53, pt1.Lookup(1200.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.46, pt1.Lookup(1400.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.43, pt1.Lookup(1500.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.22, pt1.Lookup(1750.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.2, pt1.Lookup(1800.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.11, pt1.Lookup(2000.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.11, pt1.Lookup(2500.RPMtoRad()).Double(), Tolerance); // INTERPOLATE - Assert.AreEqual(0.235, pt1.Lookup(600.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.525, pt1.Lookup(900.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.555, pt1.Lookup(1100.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.495, pt1.Lookup(1300.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.445, pt1.Lookup(1450.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.325, pt1.Lookup(1625.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.21, pt1.Lookup(1775.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.155, pt1.Lookup(1900.RPMtoRad()).Double(), TOLERANCE); - Assert.AreEqual(0.11, pt1.Lookup(2250.RPMtoRad()).Double(), TOLERANCE); - - - //TODO EXTRAPOLATE - Assert.AreEqual(0.11, pt1.Lookup(3000.RPMtoRad()).Double(), TOLERANCE); + Assert.AreEqual(0.235, pt1.Lookup(600.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.525, pt1.Lookup(900.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.555, pt1.Lookup(1100.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.495, pt1.Lookup(1300.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.445, pt1.Lookup(1450.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.325, pt1.Lookup(1625.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.21, pt1.Lookup(1775.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.155, pt1.Lookup(1900.RPMtoRad()).Double(), Tolerance); + Assert.AreEqual(0.11, pt1.Lookup(2250.RPMtoRad()).Double(), Tolerance); + + + // EXTRAPOLATE + Assert.AreEqual(0.11, pt1.Lookup(3000.RPMtoRad()).Double(), Tolerance); AssertException<VectoException>(() => pt1.Lookup(200.RPMtoRad())); AssertException<VectoException>(() => pt1.Lookup(0.RPMtoRad())); } - public static void AssertException<T>(Action func, string message = null) where T : Exception - { - try { - func(); - Assert.Fail("Expected an exception."); - } catch (T ex) { - if (!string.IsNullOrEmpty(message)) { - Assert.AreEqual(message, ex.Message); - } - } - } - [TestMethod] public void WHTCTest() { Assert.Inconclusive(); } + + public void EqualAcceleration(double velocity, double acceleration, double deceleration) + { + var entry = DeclarationData.AccelerationCurve.Lookup(velocity.SI().Kilo.Meter.Per.Hour.Cast<MeterPerSecond>()); + Assert.AreEqual(entry.Acceleration.Double(), acceleration, Tolerance); + Assert.AreEqual(entry.Deceleration.Double(), deceleration, Tolerance); + } + [TestMethod] public void AccelerationTest() { - Assert.Inconclusive(); + // FIXED POINTS + EqualAcceleration(0, 1, -1); + EqualAcceleration(25, 1, -1); + EqualAcceleration(50, 0.642857143, -1); + EqualAcceleration(60, 0.5, -0.5); + EqualAcceleration(120, 0.5, -0.5); + + // INTERPOLATED POINTS + EqualAcceleration(20, 1, -1); + EqualAcceleration(40, 0.785714286, -1); + EqualAcceleration(55, 0.571428572, -0.75); + EqualAcceleration(80, 0.5, -0.5); + EqualAcceleration(100, 0.5, -0.5); + + // EXTRAPOLATE + EqualAcceleration(-20, 1, -1); + EqualAcceleration(140, 0.5, -0.5); } [TestMethod]