altoslib: Do data analysis on raw values rather than AltosState
[fw/altos] / altoslib / AltosTimeSeries.java
index 0ea7b3561baa6e9e6390d74d3003235f9918ffae..1d3d9a6c5185878fb6400412f400c23d2a831581 100644 (file)
@@ -21,68 +21,142 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue> {
        public AltosUnits       units;
        List<AltosTimeValue>    values;
 
-       public void add(double x, double y) {
-               values.add(new AltosTimeValue(x, y));
+       public void add(AltosTimeValue tv) {
+               values.add(tv);
+       }
+
+       public void add(double time, double value) {
+               add(new AltosTimeValue(time, value));
+       }
+
+       public AltosTimeValue get(int i) {
+               return values.get(i);
+       }
+
+       public int size() {
+               return values.size();
        }
 
        public Iterator<AltosTimeValue> iterator() {
                return values.iterator();
        }
 
-       public void integrate(AltosTimeSeries integral) {
-               double  y = 0.0;
-               double  x = 0.0;
+       public double max() {
+               double max = AltosLib.MISSING;
+               for (AltosTimeValue tv : values) {
+                       if (max == AltosLib.MISSING || tv.value > max)
+                               max = tv.value;
+               }
+               return max;
+       }
+
+       public double min() {
+               double min = AltosLib.MISSING;
+               for (AltosTimeValue tv : values) {
+                       if (min == AltosLib.MISSING || tv.value < min)
+                               min = tv.value;
+               }
+               return min;
+       }
+
+       public AltosTimeSeries integrate(AltosTimeSeries integral) {
+               double  value = 0.0;
+               double  pvalue = 0.0;
+               double  time = 0.0;
                boolean start = true;
 
                for (AltosTimeValue v : values) {
                        if (start) {
-                               y = 0.0;
-                               x = v.x;
+                               value = 0.0;
                                start = false;
                        } else {
-                               y += v.y * (v.x - x);
-                               x = v.x;
+                               value += (pvalue + v.value) / 2.0 * (v.time - time);
                        }
-                       integral.add(x, y);
+                       pvalue = v.value;
+                       time = v.time;
+//                     System.out.printf("%g %g %g\n", time, v.value, value);
+                       integral.add(time, value);
+
                }
+               return integral;
        }
 
-       public void differentiate(AltosTimeSeries diff) {
-               double y = 0.0;
-               double x = 0.0;
+       public AltosTimeSeries differentiate(AltosTimeSeries diff) {
+               double value = 0.0;
+               double time = 0.0;
                boolean start = true;
 
                for (AltosTimeValue v: values) {
                        if (start) {
-                               y = 0.0;
-                               x = v.x;
+                               value = v.value;
+                               time = v.time;
                                start = false;
                        } else {
-                               double  dx = v.x - x;
-                               double  dy = v.y - y;
+                               double  dx = v.time - time;
+                               double  dy = v.value - value;
 
-                               x = v.x;
-                               y = v.y;
                                if (dx != 0)
-                                       diff.add(x, dy);
+                                       diff.add(time, dy/dx);
+
+                               time = v.time;
+                               value = v.value;
                        }
                }
+               return diff;
        }
 
        private int find_left(int i, double dt) {
                int j;
-               double t = values.get(i).x - dt;
-               for (j = i; j > 0; j--) {
-                       if (values.get(j).x < t)
+               double t = values.get(i).time - dt;
+               for (j = i; j >= 0; j--)        {
+                       if (values.get(j).time < t)
+                               break;
+               }
+               return j + 1;
+
+       }
+
+       private int find_right(int i, double dt) {
+               int j;
+               double t = values.get(i).time + dt;
+               for (j = i; j < values.size(); j++) {
+                       if (values.get(j).time > t)
                                break;
                }
-               return j;
+               return j - 1;
 
        }
 
-       public void filter(AltosTimeSeries out, double width) {
+       private double filter_coeff(double dist, double width) {
+               double ratio = dist / (width / 2);
+
+               return Math.cos(ratio * Math.PI / 2);
+       }
+
+       public AltosTimeSeries filter(AltosTimeSeries f, double width) {
+               double  half_width = width/2;
                for (int i = 0; i < values.size(); i++) {
+                       double  center_time = values.get(i).time;
+                       double  left_time = center_time - half_width;
+                       double  right_time = center_time + half_width;
+                       double  total_coeff = 0.0;
+                       double  total_value = 0.0;
+
+                       int     left = find_left(i, half_width);
+                       int     right = find_right(i, half_width);
+                       for (int j = left; j <= right; j++) {
+                               double  j_time = values.get(j).time;
+
+                               if (left_time <= j_time && j_time <= right_time) {
+                                       double  coeff = filter_coeff(j_time - center_time, width);
+                                       total_coeff += coeff;
+                                       total_value += coeff * values.get(j).value;
+                               }
+                       }
+                       if (total_coeff != 0.0)
+                               f.add(center_time, total_value / total_coeff);
                }
+               return f;
        }
 
        public AltosTimeSeries(String label, AltosUnits units) {