public Tvqs() { var t = new DateTime(2015, 01, 01, 0, 0, 0, 0); Tvq20150101 = new Tvq(t, 100, Quality.Ok); t = new DateTime(2015, 01, 05, 0, 0, 0, 0); Tvq20150105 = new Tvq(t, 105, Quality.Ok); t = new DateTime(2015, 01, 10, 0, 0, 0, 0); Tvq20150110 = new Tvq(t, 105, Quality.Ok); t = new DateTime(2015, 01, 31, 23, 59, 59); Tvq20150131 = new Tvq(t, 105, Quality.Ok); t = new DateTime(2015, 03, 01, 0, 0, 0, 0); Tvq20150301 = new Tvq(t, 110, Quality.Ok); t = new DateTime(2015, 06, 01, 0, 0, 0, 0); Tvq20150601 = new Tvq(t, 200, Quality.Ok); t = new DateTime(2015, 06, 22, 0, 0, 0, 0); Tvq20150622 = new Tvq(t, 222, Quality.Ok); t = new DateTime(2015, 06, 30, 23, 59, 59); Tvq20150630 = new Tvq(t, 230, Quality.Ok); t = new DateTime(2015, 07, 01, 0, 0, 0, 0); Tvq20150701 = new Tvq(t, 300, Quality.Ok); t = new DateTime(2015, 12, 1, 0, 0, 0); Tvq20151201 = new Tvq(t, 310, Quality.Ok); t = new DateTime(2015, 12, 31, 23, 59, 59); Tvq20151231 = new Tvq(t, 399, Quality.Ok); t = new DateTime(2016, 01, 01, 0, 0, 0, 0); Tvq20160101 = new Tvq(t, 400, Quality.Ok); t = new DateTime(2016, 02, 01, 0, 0, 0, 0); Tvq20160201 = new Tvq(t, 410, Quality.Ok); t = new DateTime(2016, 06, 01, 0, 0, 0, 0); Tvq20160601 = new Tvq(t, 500, Quality.Ok); t = new DateTime(2017, 06, 01, 0, 0, 0, 0); Tvq20170601 = new Tvq(t, 500, Quality.Ok); }
/// <summary> /// Splits a timeseries into possibly several with one timeseries per year. /// </summary> /// <param name="timeseries"></param> /// <returns></returns> public IList <Timeseries> SplitPerYear(Timeseries timeseries) { if (!timeseries.Any()) { return(new List <Timeseries>()); } var result = new List <Timeseries>(); Tvq previous = null; Timeseries currentTs = null; foreach (var tvq in timeseries) { if (previous == null) { currentTs = new Timeseries { tvq }; result.Add(currentTs); } else { if (previous.Time.Year != tvq.Time.Year) { currentTs = new Timeseries(); result.Add(currentTs); } currentTs.Add(tvq); } previous = tvq; } return(result); }
public void Apply_WhenSecondIsInterpolated_ResultIsInterpolated() { var interpolated = new Tvq(m_t0, 0, Quality.Interpolated); var result = m_Delta.Apply(m_Tvq5, interpolated); Assert.Equal(Quality.Interpolated, result.Q); }
public void Apply_WhenFirstValueIsInsidePeriod_AssumesStepwise() { // Arrange var tvq1 = new Tvq( new DateTime(2015, 01, 10, 0, 0, 0, 0), 110, Quality.Ok); var tvq2 = new Tvq( new DateTime(2015, 01, 20, 0, 0, 0, 0), 120, Quality.Ok); var ts = new Timeseries { tvq1, tvq2 }; // Act var t0 = new DateTime(2015, 01, 01, 0, 0, 0, 0); var t1 = new DateTime(2015, 01, 31, 23, 59, 59, 999); var result = new Average().Apply(t0, t1, ts); // Assert var area1 = tvq1.V * (tvq1.Time - t0).TotalSeconds; var area2 = (tvq2.Time - tvq1.Time).TotalSeconds * (tvq1.V + tvq2.V) / 2; var area3 = (t1 - tvq2.Time).TotalSeconds * tvq2.V; var expected = (area1 + area2 + area3) / (t1 - t0).TotalSeconds; Assert.Equal(expected, result.V); }
public void Apply_WhenSecondIsSuspect_ResultIsSuspect() { var suspect = new Tvq(m_t0, 0, Quality.Suspect); var result = m_Delta.Apply(m_Tvq5, suspect); Assert.Equal(Quality.Suspect, result.Q); }
public TvqEntity(string partitionKey, Tvq tvq) { PartitionKey = partitionKey; RowKey = tvq.Time.Ticks.ToString(); V = tvq.V; Q = tvq.Q; }
public DeltaTsOperatorTest() { m_Delta = new DeltaTsOperator(); m_t0 = new DateTime(2015, 01, 01, 0, 0, 0, 0); m_t1 = new DateTime(2015, 02, 01, 0, 0, 0, 0); m_t2 = new DateTime(2015, 02, 02, 0, 0, 0, 0); m_Tvq5 = new Tvq(m_t0, 5, Quality.Ok); m_Tvq7 = new Tvq(m_t1, 7, Quality.Ok); m_Tvq11 = new Tvq(m_t2, 11, Quality.Ok); }
public DeltaTvqOperatorTest() { m_Delta = new DeltaTvqOperator(); m_t0 = new DateTime(2015, 01, 01, 0, 0, 0, 0); m_t1 = new DateTime(2015, 02, 01, 0, 0, 0, 0); m_Tvq0 = new Tvq(m_t0, 0, Quality.Ok); m_Tvq6k = new Tvq(m_t0, 611000, Quality.Ok); m_Tvq999991 = new Tvq(m_t0, 999991, Quality.Ok); m_Tvq5 = new Tvq(m_t0, 5, Quality.Ok); m_Tvq7 = new Tvq(m_t1, 7, Quality.Ok); m_Tvq11 = new Tvq(m_t1, 11, Quality.Ok); m_Tvq999981 = new Tvq(m_t1, 999981, Quality.Ok); }
public void AddRegistryEntry(Tvq tvq) { // Create the table client. var tableClient = m_StorageAccount.CreateCloudTableClient(); // Create the table if it doesn't exist. var table = tableClient.GetTableReference("registryentries"); table.CreateIfNotExists(); var tvqEntity = new TvqEntity(m_PartitionKey, tvq); var insertOperation = TableOperation.Insert(tvqEntity); // Execute the insert operation. table.Execute(insertOperation); }
public void Apply_WhenPeriodStartIs10AndEndIs20_ResultIs15() { // Arrange var t0 = new DateTime(2015, 01, 01, 0, 0, 0, 0); var t1 = new DateTime(2015, 02, 01, 0, 0, 0, 0); var tvq1 = new Tvq(t0, 10, Quality.Ok); var tvq2 = new Tvq(t1, 20, Quality.Ok); var ts = new Timeseries { tvq1, tvq2 }; // Act var result = new Average().Apply(t0, t1, ts); // Assert Assert.Equal(15, result.V); }
public void Apply_WhenConstant10_ResultIs10() { // Arrange var t0 = new DateTime(2015, 01, 01, 0, 0, 0, 0); var t1 = new DateTime(2015, 02, 01, 0, 0, 0, 0); var tvq1 = new Tvq(t0, 10, Quality.Ok); var tvq2 = new Tvq(t1, 10, Quality.Ok); var ts = new Timeseries { tvq1, tvq2 }; // Act var result = new Average().Apply(t0, t1, ts); // Assert Assert.Equal(10, result.V); }
public ActionResult SubmitRegisterEntry(RegisterEntryModel model) { bool ok; DateTime t; int v; ok = DateTime.TryParse(model.DateString, out t); if (!ok) { ViewBag.Title = "Fel vid registrering"; ViewBag.SubTitle = "Datum kunde ej tolkas"; return(View(model)); } // TODO better error handling ok = int.TryParse(model.RegisterValue, out v); if (!ok) { ViewBag.Title = "Fel vid registrering"; ViewBag.SubTitle = "Mätarställning kunde ej tolkas"; return(View(model)); } // TODO better error handling var now = DateTime.Now; var isToday = t.Year == now.Year && t.Month == now.Month && t.Day == now.Day; if (isToday) { t = now; } var tvq = new Tvq(t, v, Quality.Ok); var repo = GetRegistryEntryRepo(); repo.AddRegistryEntry(tvq); ViewBag.Title = "Mätarställning registrerad"; ViewBag.SubTitle = "Mätarställningen blev registrerad"; return(View(model)); }
public Task <AddRegistryEntryResult> Handle(AddRegistryEntryCommand request, CancellationToken cancellationToken) { DateTime t; var ok = DateTime.TryParse(request.Model.DateString, out t); if (!ok) { return(Task.FromResult(new AddRegistryEntryResult(false, "Datum kunde ej tolkas"))); } // TODO better error handling int v; ok = int.TryParse(request.Model.RegisterValue, out v); if (!ok) { return(Task.FromResult(new AddRegistryEntryResult(false, "Mätarställning kunde ej tolkas"))); } // TODO better error handling var now = DateTime.Now; var isToday = t.Year == now.Year && t.Month == now.Month && t.Day == now.Day; var isMidnight = t.Hour == 0 && t.Minute == 0; if (isToday && isMidnight) { t = now; } var tvq = new Tvq(t, v, Quality.Ok); var repo = new RegistryEntryRepoFactory().GetRegistryEntryRepo(request.IdentityName); repo.AddRegistryEntry(tvq); var result = new AddRegistryEntryResult(); return(Task.FromResult(result)); }
public Tvq Apply(Tvq o1, Tvq o2) { var v = o2.V - o1.V; var isRollover = v <0 && o1.V> RolloverThresholdUpper && o2.V < RolloverThresholdLower; if (isRollover) { v = Rollover - o1.V + o2.V; } else if (v < 0 && o1.V > RolloverThresholdLower && o2.V < RolloverThresholdLower) { v = 0; } else if (Math.Abs(o2.V) < 1e-9) // The meter value is zero => new meter installed { v = 0; // Assume zero consumption. Requires meter reading just before switch so as not to lose consumption. } var q = Quality.Ok; if (o1.Q == Quality.Suspect || o2.Q == Quality.Suspect) { q = Quality.Suspect; } else if (o1.Q == Quality.Interpolated || o2.Q == Quality.Interpolated) { q = Quality.Interpolated; } return(new Tvq(o2.Time, v, q)); }
public Tvq Apply(DateTime t0, DateTime t1, Timeseries ts) { double v0 = 0; Tvq current = null; int i; int currentIndex = 0; for (i = 0; i < ts.Count; i++) { currentIndex = i; current = ts[currentIndex]; v0 = current.V; if (current.Time >= t0) { break; } } Debug.Assert(ts[currentIndex].Time >= t0); if (currentIndex > 0) { v0 = Tvq.CalculateValueAt(t0, ts[currentIndex - 1], ts[currentIndex]).V; } double area = 0; var tsHasValueWithinPeriod = current.Time <= t1; if (!tsHasValueWithinPeriod) { double v1 = 0; if (i > 0) { v1 = Tvq.CalculateValueAt(t1, ts[currentIndex - 1], ts[currentIndex]).V; } double avg = (v0 + v1) / 2; return(new Tvq(t0, avg, Quality.Interpolated)); } if (current != null) { var dt = (current.Time - t0).TotalSeconds; area = v0 * dt; } Tvq previous = null; for (i++; i < ts.Count; i++) { previous = current; current = ts[i]; if (current.Time > t1) { break; } var dt = (current.Time - previous.Time).TotalSeconds; var averageValue = (previous.V + current.V) / 2; area += averageValue * dt; } if (current.Time < t1) { var isStepwise = true; var valueAtT1 = isStepwise ? current.V // Take current value : Tvq.CalculateValueAt(t1, previous, current).V; // Extrapolate linearly var deltaT = (t1 - current.Time) .TotalSeconds; var averageValue = (current.V + valueAtT1) / 2; var lastArea = averageValue * deltaT; area += lastArea; } var average = area / (t1 - t0).TotalSeconds; return(new Tvq(t0, average, Quality.Interpolated)); }
private static Tvq CalculateDelta(Tvq current, Tvq previous) { return(DeltaOp.Apply(previous, current)); }
/// <summary> /// Inserts point at the specified interval by attempting to interpolate and/or /// extrapolate values. Useful when splitting up a period into several series /// and displaying calculated start/end values in a graph. /// </summary> /// <param name="ts"></param> /// <param name="intervalLength"></param> /// <returns>A new timeseries that has values at the start and end of the interval</returns> /// <example> /// TODO FB /// </example> public Timeseries InsertPoints(Timeseries ts, Interval intervalLength) { if (ReferenceEquals(ts, null)) { throw new ArgumentException("ts"); } var result = new Timeseries(); Tvq previous = null; for (var i = 0; i < ts.Count; i++) { var current = ts[i]; var isNewInterval = i == 0 || previous != null && IsNewInterval(previous.Time, current.Time, intervalLength); // // Previous interval end? // var doInsertPreviousEnd = isNewInterval && previous != null; // && not last second if (doInsertPreviousEnd) { var lastSecondOfPrevious = LastSecondOfInterval(previous.Time, intervalLength); var tvq = Tvq.CalculateValueAt(lastSecondOfPrevious, previous, current); result.Add(tvq); } if (previous != null) { var hasEmptyIntervalInBetween = HasEmptyIntervalInBetween(previous.Time, current.Time, intervalLength); var t = previous.Time; while (hasEmptyIntervalInBetween) { t = FirstSecondOfNextInterval(t, intervalLength); var tvq = Tvq.CalculateValueAt(t, previous, current); result.Add(tvq); var tLastSecond = LastSecondOfInterval(t, intervalLength); tvq = Tvq.CalculateValueAt(tLastSecond, previous, current); result.Add(tvq); hasEmptyIntervalInBetween = HasEmptyIntervalInBetween(t, current.Time, intervalLength); } } // // Current interval start? // var firstSecond = FirstSecond(current.Time, intervalLength); if (isNewInterval && current.Time > firstSecond) { var newTvq = previous == null ? new Tvq(firstSecond, current.V, Quality.Interpolated) : Tvq.CalculateValueAt(firstSecond, previous, current); result.Add(newTvq); } // // Add point // result.Add(current); previous = current; } if (ts.Any()) { if (previous != null) { var lastSecond = LastSecondOfInterval(previous.Time, intervalLength); var iLast = ts.Count - 1; var lastTvq = ts.Last(); if (ts.Count <= 1 && lastTvq.Time < lastSecond) { var newTvq = new Tvq(lastSecond, lastTvq.V, Quality.Interpolated); result.Add(newTvq); } else if (lastTvq.Time < lastSecond) { var newTvq = Tvq.CalculateValueAt(lastSecond, ts[iLast - 1], lastTvq); result.Add(newTvq); } } } return(result); }
/// <summary> /// Periodizes a time series with relative consumption /// </summary> /// <param name="op"></param> /// <param name="ts">A time series with relative consumption, without roll over or meter change</param> /// <param name="interval"></param> /// <returns></returns> private Timeseries Periodize(IUnaryAggregateOperator op, Timeseries ts, Interval interval) { var result = new Timeseries(); using (var enumerator = ts.GetEnumerator()) { DateTime?intervalStart = null; DateTime nextIntervalStart = DateTime.MinValue; var areMoreValues = enumerator.MoveNext(); Tvq currentTvq = null; Tvq previousTvq; Tvq nextTvq = enumerator.Current; var doNeedToMove = true; double sumForPeriod = 0; while (areMoreValues) { // Setup previous, current and next if we need to enumerator.MoveNext(); previousTvq = currentTvq; currentTvq = nextTvq; nextTvq = enumerator.Current; Debug.Assert(currentTvq != null); // Initialize interval if (!intervalStart.HasValue) { intervalStart = FirstSecond(currentTvq.Time, interval); nextIntervalStart = FirstSecondOfNextInterval(intervalStart.Value, interval); sumForPeriod = 0; } Debug.Assert(currentTvq.Time >= intervalStart); Debug.Assert(currentTvq.Time <= nextIntervalStart); do // next value may be many periods ahead { if (nextTvq == null) { if (previousTvq != null) // Prevent input with only one value from entering { sumForPeriod += currentTvq.V / (currentTvq.Time - previousTvq.Time).TotalDays * (nextIntervalStart - previousTvq.Time).TotalDays; // Extrapolate consumption to end of interval } result.Add(new Tvq(intervalStart.Value, sumForPeriod, Quality.Interpolated)); sumForPeriod = 0; } else if (nextIntervalStart <= nextTvq.Time) { doNeedToMove = false; sumForPeriod += currentTvq.V; var remainingConsumptionBelongingToThisPeriod = nextTvq.V * (nextIntervalStart - currentTvq.Time).TotalDays / (nextTvq.Time - currentTvq.Time).TotalDays; var consumptionInPeriod = sumForPeriod + remainingConsumptionBelongingToThisPeriod; result.Add(new Tvq(intervalStart.Value, consumptionInPeriod, Quality.Interpolated)); sumForPeriod = -remainingConsumptionBelongingToThisPeriod - currentTvq.V; // This is how much of nextTvq.V that we already have added. intervalStart = nextIntervalStart; nextIntervalStart = FirstSecondOfNextInterval(intervalStart.Value, interval); } else { sumForPeriod += currentTvq.V; doNeedToMove = true; } } while (!doNeedToMove); areMoreValues = nextTvq != null; } } return(result); }