From 1737fcc49e8652c4578ae55694caad1334166edf Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Fri, 17 Jul 2015 07:34:01 +0200
Subject: [PATCH] more work on distance-based simulation, adapting interfaces

---
 VectoCore/Configuration/Constants.cs          |  2 +
 .../Connector/Ports/IDrivingCyclePort.cs      | 12 +++-
 .../Models/Connector/Ports/Impl/Response.cs   |  6 ++
 .../Data/DrivingCycleData.cs                  | 38 ++++++-----
 .../Impl/DistanceBasedDrivingCycle.cs         | 65 +++++++++++++++++--
 .../Models/SimulationComponent/Impl/Driver.cs |  4 +-
 .../Impl/TimeBasedDrivingCycle.cs             |  4 +-
 .../Models/Simulation/DrivingCycleTests.cs    |  6 +-
 .../DistanceBasedDrivingCycleTest.cs          |  9 ++-
 VectoCoreTest/Utils/MockDriver.cs             | 11 +++-
 VectoCoreTest/Utils/MockPorts.cs              | 15 ++++-
 VectoCoreTest/Utils/SITest.cs                 | 12 ++--
 12 files changed, 147 insertions(+), 37 deletions(-)

diff --git a/VectoCore/Configuration/Constants.cs b/VectoCore/Configuration/Constants.cs
index f51502cbb7..0b6ece8226 100644
--- a/VectoCore/Configuration/Constants.cs
+++ b/VectoCore/Configuration/Constants.cs
@@ -28,6 +28,8 @@ namespace TUGraz.VectoCore.Configuration
 			/// simulation interval if the vehicle stands still
 			/// </summary>
 			public static readonly Meter DriveOffDistance = 1.SI<Meter>();
+
+			public const double DrivingCycleRoadGradientTolerance = 0.25;
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs b/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs
index d0a971fc1d..ab4f7669e9 100644
--- a/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs
+++ b/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs
@@ -51,9 +51,19 @@ namespace TUGraz.VectoCore.Models.Connector.Ports
 		/// Requests the Outport with the given velocity [m/s] and road gradient [rad].
 		/// </summary>
 		/// <param name="absTime">[s]</param>
-		/// <param name="dt">[s]</param>
+		/// <param name="ds"></param>
 		/// <param name="targetVelocity">[m/s]</param>
 		/// <param name="gradient">[rad]</param>
+		IResponse Request(TimeSpan absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient);
+
+		/// <summary>
+		/// Requests the outport to simulate the given time interval 
+		/// </summary>
+		/// <param name="absTime"></param>
+		/// <param name="dt"></param>
+		/// <param name="targetVelocity"></param>
+		/// <param name="gradient"></param>
+		/// <returns></returns>
 		IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSecond targetVelocity, Radian gradient);
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Connector/Ports/Impl/Response.cs b/VectoCore/Models/Connector/Ports/Impl/Response.cs
index 693086eaa2..a95af72957 100644
--- a/VectoCore/Models/Connector/Ports/Impl/Response.cs
+++ b/VectoCore/Models/Connector/Ports/Impl/Response.cs
@@ -1,4 +1,5 @@
 using System;
+using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Models.Connector.Ports.Impl
 {
@@ -33,4 +34,9 @@ namespace TUGraz.VectoCore.Models.Connector.Ports.Impl
 	{
 		public TimeSpan DeltaT { get; set; }
 	}
+
+	public class ResponseDrivingCycleDistanceExceeded : AbstractResponse
+	{
+		public Meter MaxDistance { get; set; }
+	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs b/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
index c58d689420..f202b45abe 100644
--- a/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
+++ b/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
@@ -46,22 +46,28 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			var data = VectoCSVFile.Read(fileName);
 			var entries = parser.Parse(data).ToList();
 
-			var filtered = new List<DrivingCycleEntry>();
-			var current = entries.First();
-			current.Altitude = 0.SI<Meter>();
-			filtered.Add(current);
-			foreach (var entry in entries) {
-				if (!CycleEntriesAreEqual(current, entry)) {
-					entry.Altitude = (entry.Distance - current.Distance) * Math.Sin(current.RoadGradient.Value());
-					filtered.Add(entry);
-					current = entry;
+			if (type == CycleType.DistanceBased) {
+				var filtered = new List<DrivingCycleEntry>();
+				var current = entries.First();
+				current.Altitude = 0.SI<Meter>();
+				filtered.Add(current);
+				var distance = current.Distance;
+				var altitude = current.Altitude;
+				foreach (var entry in entries) {
+					altitude += (entry.Distance - distance) * Math.Sin(entry.RoadGradient.Value());
+					distance = entry.Distance;
+					if (!CycleEntriesAreEqual(current, entry)) {
+						entry.Altitude = altitude;
+						filtered.Add(entry);
+						current = entry;
+					}
 				}
+				log.Info(string.Format("Data loaded. Number of Entries: {0}, filtered Entries: {1}", entries.Count, filtered.Count));
+				entries = filtered;
 			}
 
-			log.Info(string.Format("Data loaded. Number of Entries: {0}, filtered Entries: {1}", entries.Count, filtered.Count));
-
 			var cycle = new DrivingCycleData {
-				Entries = filtered,
+				Entries = entries,
 				Name = Path.GetFileNameWithoutExtension(fileName)
 			};
 			return cycle;
@@ -70,7 +76,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 		private static bool CycleEntriesAreEqual(DrivingCycleEntry first, DrivingCycleEntry second)
 		{
 			var retVal = first.VehicleTargetSpeed == second.VehicleTargetSpeed;
-			retVal = retVal && first.RoadGradient.IsEqual(second.RoadGradient);
+			retVal = retVal &&
+					first.RoadGradient.IsEqual(second.RoadGradient, Constants.SimulationSettings.DrivingCycleRoadGradientTolerance);
 			retVal = retVal && first.StoppingTime.IsEqual(0) && second.StoppingTime.IsEqual(0);
 			retVal = retVal && first.AdditionalAuxPowerDemand == second.AdditionalAuxPowerDemand;
 			retVal = retVal && first.AuxiliarySupplyPower.Count == second.AuxiliarySupplyPower.Count;
@@ -287,7 +294,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 				return table.Rows.Cast<DataRow>().Select(row => new DrivingCycleEntry {
 					Distance = row.ParseDouble(Fields.Distance).SI<Meter>(),
 					VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).SI().Kilo.Meter.Per.Hour.Cast<MeterPerSecond>(),
-					RoadGradient = row.ParseDoubleOrGetDefault(Fields.RoadGradient).SI().GradientPercent.Cast<Radian>(),
+					RoadGradient = (row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0).SI().GradientPercent.Cast<Radian>(),
+					StoppingTime = (row.ParseDouble(Fields.StoppingTime)).SI<Second>(),
 					AdditionalAuxPowerDemand =
 						row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.Cast<Watt>(),
 					EngineSpeed =
@@ -348,7 +356,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 				var entries = table.Rows.Cast<DataRow>().Select((row, index) => new DrivingCycleEntry {
 					Time = row.ParseDoubleOrGetDefault(Fields.Time, index).SI<Second>(),
 					VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).SI().Kilo.Meter.Per.Hour.Cast<MeterPerSecond>(),
-					RoadGradient = row.ParseDoubleOrGetDefault(Fields.RoadGradient).SI().GradientPercent.Cast<Radian>(),
+					RoadGradient = (row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0).SI().GradientPercent.Cast<Radian>(),
 					AdditionalAuxPowerDemand =
 						row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.Cast<Watt>(),
 					Gear = row.ParseDoubleOrGetDefault(Fields.Gear),
diff --git a/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
index bd069283ac..e16b4717a1 100644
--- a/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
@@ -1,5 +1,7 @@
 using System;
 using System.Linq;
+using System.Net.Cache;
+using TUGraz.VectoCore.Exceptions;
 using TUGraz.VectoCore.Models.Connector.Ports;
 using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.Simulation;
@@ -59,21 +61,57 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		IResponse ISimulationOutPort.Request(TimeSpan absTime, Meter ds)
 		{
-			//todo: Distance calculation and comparison!!!
-
 			var currentCycleEntry = Data.Entries[_currentState.CycleIndex];
-			if (currentCycleEntry.Distance.IsEqual(_currentState.Distance.Value())) {
+			var nextCycleEntry = Data.Entries[_currentState.CycleIndex + 1];
+
+			IResponse retVal = null;
+			if (currentCycleEntry.Distance.IsEqual(_previousState.Distance.Value())) {
 				// exactly on an entry in the cycle...
 				if (!currentCycleEntry.StoppingTime.IsEqual(0)) {
+					// stop for certain time...
 					if (!currentCycleEntry.VehicleTargetSpeed.IsEqual(0)) {
 						Log.WarnFormat("Stopping Time requested in cycle but target-velocity not zero. distance: {0}, target speed: {1}",
 							currentCycleEntry.StoppingTime, currentCycleEntry.VehicleTargetSpeed);
+						throw new VectoSimulationException("Stopping Time only allowed when target speed is zero!");
 					}
+					retVal = _outPort.Request(absTime, TimeSpan.FromSeconds(currentCycleEntry.StoppingTime.Value()),
+						currentCycleEntry.VehicleTargetSpeed, currentCycleEntry.RoadGradient);
+					//retVal = OutPort().Request(absTime, TimeSpan.FromSeconds(currentCycleEntry.StoppingTime.Value()));
 				}
 			}
-			//Data.
 
-			throw new NotImplementedException("Distance based Cycle is not yet implemented.");
+			if (_previousState.Distance + ds > nextCycleEntry.Distance) {
+				// only drive until next sample point in cycle
+				return new ResponseDrivingCycleDistanceExceeded() {
+					MaxDistance = nextCycleEntry.Distance - _previousState.Distance
+				};
+			}
+
+
+			retVal = DriveDistance(absTime, ds);
+			//throw new NotImplementedException("Distance based Cycle is not yet implemented.");
+		}
+
+		private IResponse DriveDistance(TimeSpan absTime, Meter ds)
+		{
+			_currentState = _previousState.Clone();
+			_currentState.Distance += ds;
+			while (_currentState.Distance < Data.Entries[_currentState.CycleIndex + 1].Distance) {
+				_currentState.CycleIndex++;
+			}
+
+			var leftSamplePoint = Data.Entries[_currentState.CycleIndex];
+			var rightSamplePoint = Data.Entries[_currentState.CycleIndex + 1];
+			_currentState.Altitude = VectoMath.Interpolate(leftSamplePoint.Distance, rightSamplePoint.Distance,
+				leftSamplePoint.Altitude, rightSamplePoint.Altitude, _currentState.Distance);
+
+			_currentState.VehicleTargetSpeed = Data.Entries[_currentState.CycleIndex].VehicleTargetSpeed;
+
+			var gradient = ((_currentState.Altitude - _previousState.Altitude) /
+							(_currentState.Distance - _previousState.Distance)).GradientPercent.Cast<Radian>();
+
+
+			return _outPort.Request(absTime, ds, _currentState.VehicleTargetSpeed, gradient);
 		}
 
 		IResponse ISimulationOutPort.Request(TimeSpan absTime, TimeSpan dt)
@@ -96,6 +134,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		#endregion
 
+		protected IResponse ProcessResponse(IResponse response) {}
+
 		#region VectoSimulationComponent
 
 		public override void CommitSimulationStep(IModalDataWriter writer)
@@ -112,10 +152,25 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public class DrivingCycleState
 		{
+			public DrivingCycleState() {}
+
+			public DrivingCycleState Clone()
+			{
+				return new DrivingCycleState() {
+					AbsTime = AbsTime,
+					Distance = Distance,
+					VehicleTargetSpeed = VehicleTargetSpeed,
+					Altitude = Altitude,
+					CycleIndex = CycleIndex
+				};
+			}
+
 			public TimeSpan AbsTime;
 
 			public Meter Distance;
 
+			public MeterPerSecond VehicleTargetSpeed;
+
 			public Meter Altitude;
 
 			public int CycleIndex;
diff --git a/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/Models/SimulationComponent/Impl/Driver.cs
index c00b79fbd1..135294610b 100644
--- a/VectoCore/Models/SimulationComponent/Impl/Driver.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/Driver.cs
@@ -27,13 +27,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			_other = other;
 		}
 
-		public IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSecond targetVelocity, Radian gradient)
+		public IResponse Request(TimeSpan absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient)
 		{
 			throw new NotImplementedException();
 		}
 
 
-		public IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSquareSecond accelleration, Radian gradient)
+		public IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSecond accelleration, Radian gradient)
 		{
 			throw new NotImplementedException();
 		}
diff --git a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
index aa02265018..5100afd79d 100644
--- a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
@@ -56,7 +56,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				return new ResponseCycleFinished();
 			}
 
-			return _outPort.Request(absTime, dt, Data.Entries[index].VehicleTargetSpeed,
+			// TODO!!
+			var dx = 0.SI<Meter>();
+			return _outPort.Request(absTime, dx, Data.Entries[index].VehicleTargetSpeed,
 				Data.Entries[index].RoadGradient);
 		}
 
diff --git a/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs b/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
index f213795b3b..31ba15de08 100644
--- a/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
+++ b/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
@@ -125,9 +125,9 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
 			Assert.IsInstanceOfType(response, typeof(ResponseSuccess));
 
 			Assert.AreEqual(absTime, outPort.AbsTime);
-			Assert.AreEqual(dt, outPort.Dt);
+			//Assert.AreEqual(dt, outPort.Ds);
 			Assert.AreEqual(0.SI<MeterPerSecond>(), outPort.Velocity);
-			Assert.AreEqual((-0.020237973).SI().GradientPercent.Cast<Radian>(), outPort.Gradient);
+			Assert.AreEqual(-0.000202379727237.SI<Radian>().Value(), outPort.Gradient.Value(), 1E-15);
 		}
 
 		[TestMethod]
@@ -151,7 +151,7 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
 
 			while (cycleOut.Request(absTime, dt) is ResponseSuccess) {
 				Assert.AreEqual(absTime, outPort.AbsTime);
-				Assert.AreEqual(dt, outPort.Dt);
+				Assert.AreEqual(dt, outPort.Ds);
 
 				var time = (absTime + TimeSpan.FromTicks(dt.Ticks / 2)).TotalSeconds;
 				var simulationInterval = dt.TotalSeconds;
diff --git a/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs b/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs
index 3a52725922..9fbc718a8b 100644
--- a/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs
+++ b/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs
@@ -1,6 +1,7 @@
 using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using TUGraz.VectoCore.FileIO.Reader.Impl;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.Simulation.Impl;
 using TUGraz.VectoCore.Models.SimulationComponent.Data;
 using TUGraz.VectoCore.Models.SimulationComponent.Impl;
@@ -29,10 +30,12 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 
 			cycle.OutPort().Initialize();
 
-			cycle.OutPort().Request(TimeSpan.FromSeconds(0), 1.SI<Meter>());
+			var response = cycle.OutPort().Request(TimeSpan.FromSeconds(0), 1.SI<Meter>());
 
-			Assert.AreEqual(18, driver.LastRequest.TargetVelocity.Value(), Tolerance);
-			Assert.AreEqual(0, driver.LastRequest.Gradient.Value(), Tolerance);
+			Assert.IsInstanceOfType(response, typeof(ResponseSuccess));
+
+			Assert.AreEqual(0, driver.LastRequest.TargetVelocity.Value(), Tolerance);
+			Assert.AreEqual(0.028416069495827, driver.LastRequest.Gradient.Value(), 1E-12);
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCoreTest/Utils/MockDriver.cs b/VectoCoreTest/Utils/MockDriver.cs
index 5f7b925e57..00149fd180 100644
--- a/VectoCoreTest/Utils/MockDriver.cs
+++ b/VectoCoreTest/Utils/MockDriver.cs
@@ -1,5 +1,6 @@
 using System;
 using TUGraz.VectoCore.Models.Connector.Ports;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.Simulation;
 using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.SimulationComponent;
@@ -28,11 +29,18 @@ namespace TUGraz.VectoCore.Tests.Utils
 			return this;
 		}
 
+		public IResponse Request(TimeSpan absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient)
+		{
+			LastRequest = new RequestData() { AbsTime = absTime, ds = ds, Gradient = gradient, TargetVelocity = targetVelocity };
+			var acc = 0.SI<MeterPerSquareSecond>();
+			return new ResponseSuccess(); //_next.Request(absTime, TimeSpan.FromSeconds(0), acc, 0.SI<Radian>());
+		}
+
 		public IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSecond targetVelocity, Radian gradient)
 		{
 			LastRequest = new RequestData() { AbsTime = absTime, dt = dt, Gradient = gradient, TargetVelocity = targetVelocity };
 			var acc = 0.SI<MeterPerSquareSecond>();
-			return _next.Request(absTime, dt, acc, 0.SI<Radian>());
+			return new ResponseSuccess(); //_next.Request(absTime, dt, acc, gradient);
 		}
 
 		public void Connect(IDriverDemandOutPort other)
@@ -43,6 +51,7 @@ namespace TUGraz.VectoCore.Tests.Utils
 		public class RequestData
 		{
 			public TimeSpan AbsTime;
+			public Meter ds;
 			public TimeSpan dt;
 			public MeterPerSecond TargetVelocity;
 			public Radian Gradient;
diff --git a/VectoCoreTest/Utils/MockPorts.cs b/VectoCoreTest/Utils/MockPorts.cs
index 44ccdfe0d6..a960a9f140 100644
--- a/VectoCoreTest/Utils/MockPorts.cs
+++ b/VectoCoreTest/Utils/MockPorts.cs
@@ -28,17 +28,30 @@ namespace TUGraz.VectoCore.Tests.Utils
 	public class MockDrivingCycleOutPort : IDrivingCycleOutPort
 	{
 		public TimeSpan AbsTime { get; set; }
+		public Meter Ds { get; set; }
+
 		public TimeSpan Dt { get; set; }
 		public MeterPerSecond Velocity { get; set; }
 		public Radian Gradient { get; set; }
 
+		public IResponse Request(TimeSpan absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient)
+		{
+			AbsTime = absTime;
+			Ds = ds;
+			Velocity = targetVelocity;
+			Gradient = gradient;
+			LogManager.GetLogger(GetType()).DebugFormat("Request: absTime: {0}, ds: {1}, velocity: {2}, gradient: {3}",
+				absTime, ds, targetVelocity, gradient);
+			return new ResponseSuccess();
+		}
+
 		public IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSecond targetVelocity, Radian gradient)
 		{
 			AbsTime = absTime;
 			Dt = dt;
 			Velocity = targetVelocity;
 			Gradient = gradient;
-			LogManager.GetLogger(GetType()).DebugFormat("Request: absTime: {0}, dt: {1}, velocity: {2}, gradient: {3}",
+			LogManager.GetLogger(GetType()).DebugFormat("Request: absTime: {0}, ds: {1}, velocity: {2}, gradient: {3}",
 				absTime, dt, targetVelocity, gradient);
 			return new ResponseSuccess();
 		}
diff --git a/VectoCoreTest/Utils/SITest.cs b/VectoCoreTest/Utils/SITest.cs
index f4bc1eda21..48b3da9991 100644
--- a/VectoCoreTest/Utils/SITest.cs
+++ b/VectoCoreTest/Utils/SITest.cs
@@ -141,12 +141,14 @@ namespace TUGraz.VectoCore.Tests.Utils
 			Assert.AreEqual((5 * 2).SI(), x * 2.0);
 
 
-			var y = 2.SI();
-			Assert.AreEqual((2 * 5).SI(), y * x);
+			//var y = 2.SI();
+			//Assert.AreEqual((2 * 5).SI(), y * x);
 
-			var percent = 10.SI<Radian>().ConvertTo().GradientPercent;
-			Assert.AreEqual(67.975.ToString("F3") + " [Percent]", percent.ToString("F3"));
-			Assert.AreEqual(67.975, percent.Value(), 0.001);
+			//var percent = 10.SI<Radian>().ConvertTo().GradientPercent;
+			//Assert.AreEqual(67.975.ToString("F3") + " [Percent]", percent.ToString("F3"));
+			//Assert.AreEqual(67.975, percent.Value(), 0.001);
+
+			Assert.AreEqual(45.0 / 180.0 * Math.PI, 1.SI().GradientPercent.Cast<Radian>().Value(), 0.000001);
 		}
 
 		[TestMethod]
-- 
GitLab