1 package org.simantics.history;
\r
3 import gnu.trove.list.array.TDoubleArrayList;
\r
5 import java.io.IOException;
\r
6 import java.math.BigDecimal;
\r
8 import org.simantics.history.csv.ExportInterpolation;
\r
9 import org.simantics.history.util.HistoryExportUtil;
\r
10 import org.simantics.history.util.StreamIterator;
\r
11 import org.simantics.history.util.ValueBand;
\r
13 public class HistorySampler {
\r
15 public synchronized static TDoubleArrayList sample( HistorySamplerItem item, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException {
\r
19 if(item.collector != null)
\r
20 item.collector.flush();
\r
21 return sample(item.iter, from, end, timeWindow, timeStep, resample);
\r
27 public static TDoubleArrayList sample( StreamIterator iter, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException {
\r
29 ExportInterpolation numberInterpolation = ExportInterpolation.LINEAR_INTERPOLATION;
\r
31 double startTime = 0.0;
\r
33 TDoubleArrayList result = new TDoubleArrayList();
\r
35 if(iter.isEmpty()) return result;
\r
37 double allFrom = iter.getFirstTime();
\r
38 double allEnd = 10e10;//iter.getLastTime();
\r
40 if(from > (allEnd + timeStep)) {
\r
41 from = allEnd-timeWindow;
\r
45 // System.err.println("sample " + from + " " + end);
\r
47 // System.err.println("fgag");
\r
50 boolean hasAnyValues = allFrom != Double.MAX_VALUE && allEnd != -Double.MAX_VALUE;
\r
52 // Make intersection of actual data range (allFrom, allEnd) and requested data (from, end)
\r
53 double _from = Double.MAX_VALUE, _end = -Double.MAX_VALUE;
\r
55 _from = Math.max(allFrom, from);
\r
56 _end = Math.min(allEnd, end);
\r
59 if (!hasAnyValues) {
\r
60 // System.err.println("=> no values");
\r
64 // Iterate until endTime is met for all variables
\r
65 double time = _from;
\r
69 // If resample is false then all samples are reported as is. The code achieves this by setting startTime to _from and timeStep to 0.0
\r
75 // time = startTime + n*timeStep
\r
77 // Sampling based on given startTime and timeStep
\r
80 // Find the first sample time that contains data
\r
81 double n = Math.max(0, Math.ceil((_from-startTime) / timeStep));
\r
82 time = startTime + n*timeStep;
\r
86 // Start sampling from startTime but make sure that it is not less than _from
\r
87 if(startTime > _from) time = startTime;
\r
94 // Must convert double times to String when initializing BigDecimal.
\r
95 // Otherwise BigDecimal will pick up inaccuracies from beyond 15 precise digits
\r
96 // thus making a mess of the time step calculations.
\r
98 BigDecimal bigTime = new BigDecimal(String.valueOf(time));
\r
99 BigDecimal bigTimeStep = new BigDecimal(String.valueOf(timeStep));
\r
101 //System.err.println("=> goto " + time);
\r
103 if(!iter.gotoTime(time)) {
\r
104 //System.err.println("=> no sample found at " + time);
\r
108 //time = iter.getValueBand().getTimeDouble();
\r
110 boolean ignore = Math.abs(time-from) < 1e-6;
\r
114 //System.err.println("process " + time + " " + iter.getValueBand());
\r
118 // Check for valid value
\r
119 if ( iter.hasValidValue() ) {
\r
123 // System.err.println("Add time : " + time);
\r
127 Object value = iter.getValueBand().getValue();
\r
128 //System.err.print("Add value : " + value);
\r
129 if (value instanceof Number) {
\r
130 if (value instanceof Float || value instanceof Double) {
\r
131 switch (numberInterpolation) {
\r
132 case PREVIOUS_SAMPLE:
\r
135 // System.err.println(" previous .. done!");
\r
136 result.add(((Number) value).doubleValue());
\r
141 case LINEAR_INTERPOLATION:
\r
142 if (time != iter.getValueBand().getTimeDouble() && iter.hasNext()) {
\r
145 int currentIndex = iter.getIndex();
\r
146 ValueBand band = iter.getValueBand();
\r
147 //double t1 = band.getTimeDouble();
\r
148 Number v1 = (Number) value;
\r
149 double t12 = band.getEndTimeDouble();
\r
151 double t2 = iter.getValueBand().getTimeDouble();
\r
152 Number v2 = (Number) iter.getValueBand().getValue();
\r
153 iter.gotoIndex(currentIndex);
\r
155 double vs = v1.doubleValue();
\r
157 vs = HistoryExportUtil.biglerp(t12, v1.doubleValue(), t2, v2.doubleValue(), time);
\r
160 // System.err.println(" linear .. done!");
\r
165 // Exact timestamp match, or last sample.
\r
166 // Don't interpolate nor extrapolate.
\r
168 // System.err.println(" else .. done!");
\r
169 result.add(((Number) value).doubleValue());
\r
174 throw new UnsupportedOperationException("Unsupported interpolation: " + numberInterpolation);
\r
177 throw new IllegalStateException("Value is not a number " + value);
\r
179 } else if (value instanceof Boolean) {
\r
181 result.add( (Boolean)value ? 1.0: 0.0);
\r
183 throw new IllegalStateException("Value is not a number " + value);
\r
189 // Read next values, and the following times
\r
190 if ( timeStep>0.0 ) {
\r
191 bigTime = bigTime.add(bigTimeStep);
\r
192 time = bigTime.doubleValue();
\r
194 // Get smallest end time that is larger than current time
\r
195 Double nextTime = null;
\r
196 // System.out.println("time = "+time);
\r
197 if(!iter.hasNext()) break;
\r
198 Double itemNextTime = iter.getNextTime( time );
\r
199 // System.err.println(" "+i.label+" nextTime="+itemNextTime);
\r
200 if ( nextTime == null || ( nextTime > itemNextTime && !itemNextTime.equals( time ) ) ) nextTime = itemNextTime;
\r
201 if ( nextTime == null || nextTime.equals( time ) ) break;
\r
205 boolean hasMore = false;
\r
207 iter.proceedToTime(time);
\r
208 if(HistoryExportUtil.contains(iter, time)) hasMore = true;
\r
210 if(!hasMore) break;
\r
212 } while (time<=_end);
\r
214 //System.err.println("=> " + Arrays.toString(result.toArray()));
\r