From f04c693aa1b59dbd0b62eeec14e787ac25db6e93 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Thu, 20 Oct 2016 16:17:19 +0200
Subject: [PATCH] bugfix: 1 hz vehicle going backwards

---
 .../OutputData/ModalDataContainer.cs          | 116 +++++++++++-------
 1 file changed, 74 insertions(+), 42 deletions(-)

diff --git a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs
index 4179e4d6df..d39c65fdac 100644
--- a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs
+++ b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs
@@ -35,6 +35,8 @@ using System.Data;
 using System.Globalization;
 using System.Linq;
 using System.Runtime.CompilerServices;
+using TUGraz.VectoCommon.Exceptions;
+using TUGraz.VectoCommon.Models;
 using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.Simulation.Impl;
@@ -71,7 +73,6 @@ namespace TUGraz.VectoCore.OutputData
 
 		protected ModalDataContainer(string runName, string cycleName, string runSuffix, IModalDataWriter writer,
 			Action<ModalDataContainer> addReportResult, bool writeEngineOnly, params IModalDataFilter[] filters)
-
 		{
 			HasTorqueConverter = false;
 			RunName = runName;
@@ -305,74 +306,101 @@ namespace TUGraz.VectoCore.OutputData
 		{
 			public ModalResults Filter(ModalResults data)
 			{
-				var absTime = 0.SI<Second>();
-				var distance = 0.SI<Meter>();
 				var results = (ModalResults)data.Clone();
 
-				var remainingDt = 0.SI<Second>();
-
 				object[] remainingRow = null;
 				var gearsList = new Dictionary<object, Second>(3);
-				var vAct = data.Rows.Cast<DataRow>().First().Field<MeterPerSecond>((int)ModalResultField.v_act);
 
-				foreach (DataRow row in data.Rows) {
+				var absTime = 0.SI<Second>();
+				var distance = 0.SI<Meter>();
+				var v = data.Rows[0].Field<MeterPerSecond>((int)ModalResultField.v_act);
+				var remainingDt = 0.SI<Second>();
+				var vPrevious = v;
+
+				for (var i = 0; i < data.Rows.Count; i++) {
+					var row = data.Rows[i];
+
 					var currentDt = row.Field<Second>((int)ModalResultField.simulationInterval);
-					distance = row.Field<Meter>((int)ModalResultField.dist);
 
-					// if current + remaining time >= 1 second: take remaining row and split up currentRow to fill up 1 second.
-					if (remainingDt > 0 && remainingDt + currentDt >= 1) {
-						var diffDt = 1.SI<Second>() - remainingDt;
-						var r = results.NewRow();
+					if (row.Field<Meter>((int)ModalResultField.dist).IsSmaller(distance, 1e-3))
+						LogManager.GetLogger(typeof(ModalData1HzFilter).FullName).Error("1Hz-Filter: distance must always be increasing.");
 
+					// if a remainder and currentDt would exceed 1 second: take remainder and take current row to fill up to 1 second.
+					if (remainingDt > 0 && remainingDt + currentDt >= 1) {
+						// calculate values
+						var dt = 1.SI<Second>() - remainingDt;
 						var gear = row[(int)ModalResultField.Gear];
-						gearsList[gear] = gearsList.GetValueOrZero(gear) + diffDt;
-
-						distance += diffDt * vAct + diffDt * diffDt * (MeterPerSquareSecond)row[(int)ModalResultField.acc] / 2;
-						vAct += diffDt * (MeterPerSquareSecond)row[(int)ModalResultField.acc];
-						r.ItemArray = AddRow(remainingRow, MultiplyRow(row.ItemArray, diffDt));
-						absTime += diffDt;
+						gearsList[gear] = gearsList.GetValueOrZero(gear) + dt;
+						var a = (MeterPerSquareSecond)row[(int)ModalResultField.acc];
+						var ds = dt * v + a / 2 * dt * dt;
+						if (ds.IsSmaller(0))
+							throw new VectoSimulationException("1Hz-Filter: simulation distance must not be negative.");
+						absTime += dt;
+						v += dt * a;
+						distance += ds;
 
+						// write a new row for the combined 1 second
+						var r = results.NewRow();
+						r.ItemArray = AddRow(remainingRow, MultiplyRow(row.ItemArray, dt));
 						r[(int)ModalResultField.time] = absTime;
 						r[(int)ModalResultField.simulationInterval] = 1.SI<Second>();
 						r[(int)ModalResultField.Gear] = gearsList.MaxBy(kv => kv.Value).Key;
 						r[(int)ModalResultField.dist] = distance;
-						r[(int)ModalResultField.v_act] = vAct;
+						r[(int)ModalResultField.v_act] = (v + vPrevious) / 2;
+						vPrevious = v;
+						results.Rows.Add(r);
 
+						// reset remainder
+						// reduce current dt by already taken diff
 						gearsList.Clear();
-						results.Rows.Add(r);
-						currentDt -= diffDt;
+						currentDt -= dt;
 						remainingDt = 0.SI<Second>();
 						remainingRow = null;
 					}
 
 					// if current row still longer than 1 second: split it to 1 second slices until it is < 1 second
 					while (currentDt >= 1) {
-						currentDt = currentDt - 1.SI<Second>();
+						// calculate values
 						var dt = 1.SI<Second>();
-						var r = results.NewRow();
-						r.ItemArray = row.ItemArray;
+						currentDt = currentDt - 1.SI<Second>();
+						var a = (MeterPerSquareSecond)row[(int)ModalResultField.acc];
+						var ds = v * dt + a / 2 * dt * dt;
+						if (ds.IsSmaller(0))
+							throw new VectoSimulationException("1Hz-Filter: simulation distance must not be negative.");
 						absTime += dt;
-						distance += dt * vAct + dt * dt * (MeterPerSquareSecond)row[(int)ModalResultField.acc] / 2;
-						vAct += dt * (MeterPerSquareSecond)row[(int)ModalResultField.acc];
+						v += a * dt;
+						distance += ds;
 
+						// write a new row for the sliced 1 second
+						var r = results.NewRow();
+						r.ItemArray = row.ItemArray;
 						r[(int)ModalResultField.time] = absTime;
 						r[(int)ModalResultField.simulationInterval] = dt;
 						r[(int)ModalResultField.dist] = distance;
-						r[(int)ModalResultField.v_act] = vAct;
+						r[(int)ModalResultField.v_act] = (v + vPrevious) / 2;
+						vPrevious = v;
 						results.Rows.Add(r);
 					}
 
-					// if the there still is something left in current row: add the weighted values to remainder-buffer
+					// if there still is something left in current row: add to weighted values to remainder
 					if (currentDt > 0) {
+						// calculate values
+						var dt = currentDt;
 						var gear = row[(int)ModalResultField.Gear];
-						gearsList[gear] = gearsList.GetValueOrZero(gear) + currentDt;
+						gearsList[gear] = gearsList.GetValueOrZero(gear) + dt;
+						var a = (MeterPerSquareSecond)row[(int)ModalResultField.acc];
+						var ds = v * dt + a / 2 * dt * dt;
+						if (ds.IsSmaller(0))
+							throw new VectoSimulationException("1Hz-Filter: simulation distance must not be negative.");
+						absTime += dt;
+						v += a * dt;
+						distance += ds;
 
-						distance += currentDt * vAct + currentDt * currentDt * (MeterPerSquareSecond)row[(int)ModalResultField.acc] / 2;
-						vAct += currentDt * (MeterPerSquareSecond)row[(int)ModalResultField.acc];
-						remainingRow = AddRow(remainingRow, MultiplyRow(row.ItemArray, currentDt));
-						remainingDt += currentDt;
-						absTime += currentDt;
+						// add to remainder
+						remainingRow = AddRow(remainingRow, MultiplyRow(row.ItemArray, dt));
+						remainingDt += dt;
 					} else {
+						// reset remainder (just to be sure!)
 						remainingRow = null;
 						remainingDt = 0.SI<Second>();
 						gearsList.Clear();
@@ -380,21 +408,25 @@ namespace TUGraz.VectoCore.OutputData
 				}
 
 				// if last row was not enough to full second: take last row as whole second
-
 				if (remainingDt > 0) {
+					// calculate values
 					var last = data.Rows.Cast<DataRow>().Last();
+					var dt = remainingDt;
+					var a = (MeterPerSquareSecond)last[(int)ModalResultField.acc];
+					var ds = v * dt + a / 2 * dt * dt;
+					if (ds.IsSmaller(0))
+						throw new VectoSimulationException("1Hz-Filter: simulation distance must not be negative.");
+					v += a * dt;
+					distance += ds;
+
+					// write a new row for the last second
 					var r = results.NewRow();
-
-					r.ItemArray = MultiplyRow(remainingRow, 1 / remainingDt).ToArray();
-					distance += remainingDt * vAct +
-								remainingDt * remainingDt * (MeterPerSquareSecond)last[(int)ModalResultField.acc] / 2;
-					vAct += remainingDt * (MeterPerSquareSecond)last[(int)ModalResultField.acc];
-
+					r.ItemArray = MultiplyRow(remainingRow, 1 / dt).ToArray();
 					r[(int)ModalResultField.time] = VectoMath.Ceiling(absTime);
 					r[(int)ModalResultField.simulationInterval] = 1.SI<Second>();
 					r[(int)ModalResultField.Gear] = gearsList.MaxBy(kv => kv.Value).Key;
 					r[(int)ModalResultField.dist] = distance;
-					r[(int)ModalResultField.v_act] = vAct;
+					r[(int)ModalResultField.v_act] = (v + vPrevious) / 2;
 					results.Rows.Add(r);
 				}
 
-- 
GitLab