+ public AltosTimeValue max() {
+ AltosTimeValue max = null;
+ for (AltosTimeValue tv : values)
+ if (max == null || tv.value > max.value)
+ max = tv;
+ return max;
+ }
+
+ 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 == null || tv.value > max.value)
+ max = tv;
+ }
+ return max;
+ }
+
+ public AltosTimeValue min() {
+ AltosTimeValue min = null;
+ for (AltosTimeValue tv : values) {
+ if (min == null || tv.value < min.value)
+ min = tv;
+ }
+ return min;
+ }
+
+ 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 == 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_value = 0;
+ double total_time = 0;
+ AltosTimeValue prev = null;
+ for (AltosTimeValue tv : values) {
+ if (prev != null) {
+ total_value += (tv.value + prev.value) / 2 * (tv.time - prev.time);
+ total_time += (tv.time - prev.time);
+ }
+ prev = tv;
+ }
+ if (total_time == 0)
+ return AltosLib.MISSING;
+ return total_value / total_time;
+ }
+
+ public double average(double start_time, double end_time) {
+ double total_value = 0;
+ double total_time = 0;
+ AltosTimeValue prev = null;
+ for (AltosTimeValue tv : values) {
+ if (start_time <= tv.time && tv.time <= end_time) {
+ 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 (total_time == 0)
+ return AltosLib.MISSING;
+ return total_value / total_time;
+ }
+
+ 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) {
+ value = 0.0;
+ start = false;
+ } else {
+ value += (pvalue + v.value) / 2.0 * (v.time - time);
+ }
+ pvalue = v.value;
+ time = v.time;
+ integral.add(time, value);
+
+ }
+ return integral;
+ }
+
+ public AltosTimeSeries differentiate(AltosTimeSeries diff) {
+ double value = 0.0;
+ double time = 0.0;
+ boolean start = true;
+
+ for (AltosTimeValue v: values) {
+ if (start) {
+ value = v.value;
+ time = v.time;
+ start = false;
+ } else {
+ double dx = v.time - time;
+ double dy = v.value - value;
+
+ if (dx != 0)
+ 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).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 - 1;
+
+ }
+
+ private static double i0(double x) {
+ double ds = 1, d = 0, s = 0;
+
+ 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;
+ 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 j_left = j == left ? left_time : values.get(j-1).time;
+ 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 += partial;
+ }
+ }
+ if (total_coeff != 0.0)
+ f.add(center_time, total_value / total_coeff);
+ }
+ return f;
+ }
+