2 * Copyright © 2017 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 package org.altusmetrum.altoslib_11;
19 public class AltosTimeSeries implements Iterable<AltosTimeValue> {
21 public AltosUnits units;
22 ArrayList<AltosTimeValue> values;
24 public void add(AltosTimeValue tv) {
28 public void add(double time, double value) {
29 add(new AltosTimeValue(time, value));
32 public AltosTimeValue get(int i) {
36 private double lerp(AltosTimeValue v0, AltosTimeValue v1, double t) {
38 if (v0.time == v1.time)
39 return (v0.value + v1.value) / 2;
41 return (v0.value * (v1.time - t) + v1.value * (t - v0.time)) / v1.time - v0.time;
44 private int after_index(double time) {
46 int hi = values.size() - 1;
49 int mid = (lo + hi) / 2;
51 if (values.get(mid).time < time)
59 /* Compute a value for an arbitrary time */
60 public double value(double time) {
61 int after = after_index(time);
63 return values.get(0).value;
64 if (after == values.size())
65 return values.get(after - 1).value;
67 return lerp(values.get(after-1), values.get(after), time);
70 /* Find the value just before an arbitrary time */
71 public double value_before(double time) {
72 int after = after_index(time);
75 return values.get(0).value;
76 return values.get(after-1).value;
79 /* Find the value just after an arbitrary time */
80 public double value_after(double time) {
81 int after = after_index(time);
83 if (after == values.size())
84 return values.get(after-1).value;
85 return values.get(after).value;
92 public Iterator<AltosTimeValue> iterator() {
93 return values.iterator();
97 double max = AltosLib.MISSING;
98 for (AltosTimeValue tv : values) {
99 if (max == AltosLib.MISSING || tv.value > max)
105 public double min() {
106 double min = AltosLib.MISSING;
107 for (AltosTimeValue tv : values) {
108 if (min == AltosLib.MISSING || tv.value < min)
114 public AltosTimeSeries integrate(AltosTimeSeries integral) {
118 boolean start = true;
120 for (AltosTimeValue v : values) {
125 value += (pvalue + v.value) / 2.0 * (v.time - time);
129 // System.out.printf("%g %g %g\n", time, v.value, value);
130 integral.add(time, value);
136 public AltosTimeSeries differentiate(AltosTimeSeries diff) {
139 boolean start = true;
141 for (AltosTimeValue v: values) {
147 double dx = v.time - time;
148 double dy = v.value - value;
151 diff.add(time, dy/dx);
160 private int find_left(int i, double dt) {
162 double t = values.get(i).time - dt;
163 for (j = i; j >= 0; j--) {
164 if (values.get(j).time < t)
171 private int find_right(int i, double dt) {
173 double t = values.get(i).time + dt;
174 for (j = i; j < values.size(); j++) {
175 if (values.get(j).time > t)
182 private double filter_coeff(double dist, double width) {
183 double ratio = dist / (width / 2);
185 return Math.cos(ratio * Math.PI / 2);
188 public AltosTimeSeries filter(AltosTimeSeries f, double width) {
189 double half_width = width/2;
190 for (int i = 0; i < values.size(); i++) {
191 double center_time = values.get(i).time;
192 double left_time = center_time - half_width;
193 double right_time = center_time + half_width;
194 double total_coeff = 0.0;
195 double total_value = 0.0;
197 int left = find_left(i, half_width);
198 int right = find_right(i, half_width);
200 for (int j = left; j <= right; j++) {
201 double j_time = values.get(j).time;
203 if (left_time <= j_time && j_time <= right_time) {
204 double j_left = j == left ? left_time : values.get(j-1).time;
205 double j_right = j == right ? right_time : values.get(j+1).time;
206 double interval = (j_right - j_left) / 2.0;
207 double coeff = filter_coeff(j_time - center_time, width) * interval;
209 total_coeff += coeff;
210 total_value += coeff * values.get(j).value;
213 if (total_coeff != 0.0)
214 f.add(center_time, total_value / total_coeff);
219 public AltosTimeSeries(String label, AltosUnits units) {
222 this.values = new ArrayList<AltosTimeValue>();