diff --git a/java_console/models/src/com/rusefi/TimeBasedBuffer.java b/java_console/models/src/com/rusefi/TimeBasedBuffer.java index 081c2f5b03..2ebccbab42 100644 --- a/java_console/models/src/com/rusefi/TimeBasedBuffer.java +++ b/java_console/models/src/com/rusefi/TimeBasedBuffer.java @@ -1,4 +1,47 @@ package com.rusefi; -public class TimeBasedBuffer { +import java.util.TreeMap; + +/** + * Last X seconds of values. + *

+ * This data structure holds only one value for each millisecond timestamp but that should be totally fine + * for our purposes + * + * @see EtbTestSequence + */ +public class TimeBasedBuffer implements DataBuffer { + private final TreeMap values = new TreeMap<>(); + private final long duration; + + public TimeBasedBuffer(long duration) { + this.duration = duration; + } + + private synchronized void truncate() { + long now = currentTimeMillis(); + values.headMap(now - duration).clear(); + } + + protected long currentTimeMillis() { + return System.currentTimeMillis(); + } + + public synchronized void add(double value) { + values.put(currentTimeMillis(), value); + } + + public synchronized int getSize() { + truncate(); + return values.size(); + } + + public synchronized double[] getValues() { + truncate(); + double[] result = new double[values.size()]; + int i = 0; + for (Double v : values.values()) + result[i++] = v; + return result; + } } diff --git a/java_console/models/src/com/rusefi/test/TimeBasedBufferTest.java b/java_console/models/src/com/rusefi/test/TimeBasedBufferTest.java index 926a7fefd2..03661daca2 100644 --- a/java_console/models/src/com/rusefi/test/TimeBasedBufferTest.java +++ b/java_console/models/src/com/rusefi/test/TimeBasedBufferTest.java @@ -1,4 +1,51 @@ package com.rusefi.test; +import com.rusefi.DataBuffer; +import com.rusefi.TimeBasedBuffer; +import org.junit.Test; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + public class TimeBasedBufferTest { + @Test + public void testRealTruncate() throws InterruptedException { + TimeBasedBuffer b = new TimeBasedBuffer(100); + b.add(1); + System.out.println(b.getSize()); // cannot really test size here since who know how time flies + b.add(2); + b.add(1); + System.out.println(b.getSize()); // cannot really test size here since who know how time flies + Thread.sleep(200); + assertEquals(0, b.getSize()); + } + + @Test + public void testTruncate() { + AtomicLong time = new AtomicLong(); + TimeBasedBuffer b = new TimeBasedBuffer(100) { + @Override + protected long currentTimeMillis() { + return time.get(); + } + }; + + b.add(1); + assertEquals(1, b.getSize()); + b.add(2); + assertEquals(1, b.getSize()); // value for same timestamp is overriden + time.set(3); + b.add(3); + assertEquals(2, b.getSize()); // value for same timestamp is overriden + double[] v = b.getValues(); + assertTrue(Arrays.equals(new double[]{2, 3}, v)); + + assertEquals(0.707106, DataBuffer.getStandardDeviation(b.getValues()), 0.001); + + time.set(150); + assertEquals(0, b.getSize()); + } } diff --git a/java_console/ui/src/com/rusefi/ui/widgets/EtbTestSequence.java b/java_console/ui/src/com/rusefi/ui/widgets/EtbTestSequence.java index 40a1964dbb..a735b14eeb 100644 --- a/java_console/ui/src/com/rusefi/ui/widgets/EtbTestSequence.java +++ b/java_console/ui/src/com/rusefi/ui/widgets/EtbTestSequence.java @@ -2,6 +2,7 @@ package com.rusefi.ui.widgets; import com.rusefi.FileLog; import com.rusefi.SensorSnifferCentral; +import com.rusefi.TimeBasedBuffer; import com.rusefi.core.Sensor; import com.rusefi.core.SensorCentral; import com.rusefi.io.CommandQueue; @@ -19,6 +20,8 @@ import java.util.concurrent.TimeUnit; *

* 11/16/2017 * (c) Andrey Belomutskiy + * + * @see TimeBasedBuffer */ public class EtbTestSequence { private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();