X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=altoslib%2FAltosTimeSeries.java;h=80720f152c3bf3d232d6c8ae33d768fe1f1478fd;hp=142c30ef2d794818b455b17ca59533b28cdf6533;hb=52149fd81df45f37f5097850795f290f463c43ef;hpb=2e82051a6aaaccf1e8a242f9c8141e4167e652d2 diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index 142c30ef..80720f15 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -12,19 +12,41 @@ * General Public License for more details. */ -package org.altusmetrum.altoslib_11; +package org.altusmetrum.altoslib_14; import java.util.*; -public class AltosTimeSeries implements Iterable { +public class AltosTimeSeries implements Iterable, Comparable { public String label; public AltosUnits units; ArrayList values; + boolean data_changed; + double min_time = -2; + + public int compareTo(AltosTimeSeries other) { + return label.compareTo(other.label); + } public void add(AltosTimeValue tv) { - values.add(tv); + if (tv.time >= min_time) { + data_changed = true; + values.add(tv); + } + } + + public void erase_values() { + data_changed = true; + this.values = new ArrayList(); + } + + public void clear_changed() { + data_changed = false; } +// public boolean changed() { +// return data_changed; +// } + public void add(double time, double value) { add(new AltosTimeValue(time, value)); } @@ -38,7 +60,7 @@ public class AltosTimeSeries implements Iterable { if (v0.time == v1.time) return (v0.value + v1.value) / 2; - return (v0.value * (v1.time - t) + v1.value * (t - v0.time)) / v1.time - v0.time; + return (v0.value * (v1.time - t) + v1.value * (t - v0.time)) / (v1.time - v0.time); } private int after_index(double time) { @@ -59,12 +81,18 @@ public class AltosTimeSeries implements Iterable { /* Compute a value for an arbitrary time */ public double value(double time) { int after = after_index(time); - if (after == 0) - return values.get(0).value; - if (after == values.size()) - return values.get(after - 1).value; + double ret; - return lerp(values.get(after-1), values.get(after), time); + if (after == 0) + ret = values.get(0).value; + else if (after == values.size()) + ret = values.get(after - 1).value; + else { + AltosTimeValue b = values.get(after-1); + AltosTimeValue a = values.get(after); + ret = lerp(b, a, time); + } + return ret; } /* Find the value just before an arbitrary time */ @@ -103,68 +131,88 @@ public class AltosTimeSeries implements Iterable { return values.iterator(); } - public double max() { - double max = AltosLib.MISSING; - for (AltosTimeValue tv : values) { - if (max == AltosLib.MISSING || tv.value > max) - max = tv.value; - } + public AltosTimeValue max() { + AltosTimeValue max = null; + for (AltosTimeValue tv : values) + if (max == null || tv.value > max.value) + max = tv; return max; } - public double max(double start_time, double end_time) { - double max = AltosLib.MISSING; + public AltosTimeValue max(double start_time, double end_time) { + AltosTimeValue max = null; for (AltosTimeValue tv : values) { if (start_time <= tv.time && tv.time <= end_time) - if (max == AltosLib.MISSING || tv.value > max) - max = tv.value; + if (max == null || tv.value > max.value) + max = tv; } return max; } - public double min() { - double min = AltosLib.MISSING; + public AltosTimeValue min() { + AltosTimeValue min = null; for (AltosTimeValue tv : values) { - if (min == AltosLib.MISSING || tv.value < min) - min = tv.value; + if (min == null || tv.value < min.value) + min = tv; } return min; } - public double min(double start_time, double end_time) { - double min = AltosLib.MISSING; + public AltosTimeValue min(double start_time, double end_time) { + AltosTimeValue min = null; for (AltosTimeValue tv : values) { if (start_time <= tv.time && tv.time <= end_time) - if (min == AltosLib.MISSING || tv.value < min) - min = tv.value; + if (min == null || tv.value < min.value) + min = tv; } return min; } + public AltosTimeValue first() { + if (values.size() > 0) + return values.get(0); + return null; + } + + public AltosTimeValue last() { + if (values.size() > 0) + return values.get(values.size() - 1); + return null; + } + public double average() { - double total = 0; - int count = 0; + double total_value = 0; + double total_time = 0; + AltosTimeValue prev = null; for (AltosTimeValue tv : values) { - total += tv.value; - count++; + if (prev != null) { + total_value += (tv.value + prev.value) / 2 * (tv.time - prev.time); + total_time += (tv.time - prev.time); + } + prev = tv; } - if (count == 0) + if (total_time == 0) return AltosLib.MISSING; - return total / count; + return total_value / total_time; } public double average(double start_time, double end_time) { - double total = 0; - int count = 0; + double total_value = 0; + double total_time = 0; + AltosTimeValue prev = null; for (AltosTimeValue tv : values) { if (start_time <= tv.time && tv.time <= end_time) { - total += tv.value; - count++; + if (prev != null) { + total_value += (tv.value + prev.value) / 2 * (tv.time - start_time); + total_time += (tv.time - start_time); + } + start_time = tv.time; } + prev = tv; } - if (count == 0) + if (total_time == 0) return AltosLib.MISSING; - return total / count; + return total_value / total_time; } public AltosTimeSeries integrate(AltosTimeSeries integral) { @@ -182,7 +230,6 @@ public class AltosTimeSeries implements Iterable { } pvalue = v.value; time = v.time; -// System.out.printf("%g %g %g\n", time, v.value, value); integral.add(time, value); } @@ -235,14 +282,35 @@ public class AltosTimeSeries implements Iterable { } - private double filter_coeff(double dist, double width) { - double ratio = dist / (width / 2); + private static double i0(double x) { + double ds = 1, d = 0, s = 0; - return Math.cos(ratio * Math.PI / 2); + do { + d += 2; + ds = ds * (x * x) / (d * d); + s += ds; + } while (ds - 0.2e-8 * s > 0); + return s; + } + + private static double kaiser(double n, double m, double beta) { + double alpha = m / 2; + double t = (n - alpha) / alpha; + + if (t > 1 || t < -1) + t = 1; + double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta); + return k; + } + + private double filter_coeff(double dist, double width) { + return kaiser(dist + width/2.0, width, 2 * Math.PI); } public AltosTimeSeries filter(AltosTimeSeries f, double width) { + double half_width = width/2; + int half_point = values.size() / 2; for (int i = 0; i < values.size(); i++) { double center_time = values.get(i).time; double left_time = center_time - half_width; @@ -261,9 +329,11 @@ public class AltosTimeSeries implements Iterable { double j_right = j == right ? right_time : values.get(j+1).time; double interval = (j_right - j_left) / 2.0; double coeff = filter_coeff(j_time - center_time, width) * interval; + double value = values.get(j).value; + double partial = value * coeff; total_coeff += coeff; - total_value += coeff * values.get(j).value; + total_value += partial; } } if (total_coeff != 0.0)