diff --git a/java_console/ui/src/com/rusefi/BenchTestPane.java b/java_console/ui/src/com/rusefi/BenchTestPane.java index 6a895c1517..3a4d72b85f 100644 --- a/java_console/ui/src/com/rusefi/BenchTestPane.java +++ b/java_console/ui/src/com/rusefi/BenchTestPane.java @@ -2,6 +2,7 @@ package com.rusefi; import com.rusefi.ui.MessagesView; import com.rusefi.ui.util.UiUtils; +import com.rusefi.ui.widgets.EtbMonteCarloSequence; import com.rusefi.ui.widgets.EtbResearch; import com.rusefi.ui.widgets.EtbTestSequence; import org.jetbrains.annotations.NotNull; @@ -25,6 +26,7 @@ public class BenchTestPane { content.add(createIdleTest()); content.add(createDizzyTest()); content.add(UiUtils.wrap(new EtbTestSequence().getButton())); + content.add(UiUtils.wrap(new EtbMonteCarloSequence().getButton())); content.add(UiUtils.wrap(new EtbResearch().getButton())); content.add(new MessagesView().messagesScroll); } diff --git a/java_console/ui/src/com/rusefi/ui/widgets/ClosedLoopControlQualityMetric.java b/java_console/ui/src/com/rusefi/ui/widgets/ClosedLoopControlQualityMetric.java index d2b8099892..5198e6af09 100644 --- a/java_console/ui/src/com/rusefi/ui/widgets/ClosedLoopControlQualityMetric.java +++ b/java_console/ui/src/com/rusefi/ui/widgets/ClosedLoopControlQualityMetric.java @@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit; /** * https://github.com/rusefi/rusefi/issues/494 *

+ * https://en.wikipedia.org/wiki/Standard_deviation of error posted to specified sensor + *

* 11/16/2017 * (c) Andrey Belomutskiy * @@ -25,6 +27,7 @@ public class ClosedLoopControlQualityMetric { private final ValueSource target; private final ValueSource result; private final Sensor destination; + private boolean isStarted; /** * Buffer of recent error measurements @@ -43,6 +46,10 @@ public class ClosedLoopControlQualityMetric { } public void start(int bufferSize, int periodMs) { + if (isStarted) + return; + isStarted = true; + errorsBuffer = new CyclicBuffer(bufferSize); executor.scheduleAtFixedRate(() -> { rememberCurrentError(target.getValue() - result.getValue()); diff --git a/java_console/ui/src/com/rusefi/ui/widgets/EtbMonteCarloSequence.java b/java_console/ui/src/com/rusefi/ui/widgets/EtbMonteCarloSequence.java new file mode 100644 index 0000000000..e1508b820b --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/widgets/EtbMonteCarloSequence.java @@ -0,0 +1,73 @@ +package com.rusefi.ui.widgets; + +import com.rusefi.core.MessagesCentral; +import com.rusefi.core.Sensor; +import com.rusefi.core.SensorCentral; +import com.rusefi.io.CommandQueue; + +import javax.swing.*; + +import java.util.Random; + +import static com.rusefi.Timeouts.SECOND; +import static com.rusefi.ui.widgets.EtbTestSequence.*; + +/** + * 3/2/2019 + * (c) Andrey Belomutskiy + */ +public class EtbMonteCarloSequence { + public static final int LIMIT = 100; + private final JButton button = new JButton("ETB I feel lucky!"); + private final static Random r = new Random(); + private int counter; + + public EtbMonteCarloSequence() { + button.addActionListener(e -> { + counter = 0; + + // 3000 data points at 10Hz should be 300 seconds worth of data + metric.start(/* buffer size: */3000, /*period, ms: */ 100); + + executor.execute(this::runRandomCycle); + }); + } + + private void runRandomCycle() { + final int offset = r.nextInt(100); + final double pFactor = 1 + (r.nextInt(300) / 100.0); + final double iFactor = r.nextInt(30) / 100.0; + final double dFactor = r.nextInt(30) / 100.0; + String stats = "mcstats:offset:" + offset + + ":pFactor:" + pFactor + + ":iFactor:" + iFactor + + ":dFactor:" + dFactor; + MessagesCentral.getInstance().postMessage(EtbMonteCarloSequence.class, stats); + CommandQueue.getInstance().write("set etb_o " + offset); + CommandQueue.getInstance().write("set etb_p " + pFactor); + CommandQueue.getInstance().write("set etb_i " + iFactor); + CommandQueue.getInstance().write("set etb_d " + dFactor); + + SequenceStep firstStep = new EtbTarget(10 * SECOND, 4 /*position*/); + SequenceStep last = addSequence(firstStep); + last.addNext(new SequenceStep(5 * SECOND) { + @Override + protected void doJob() { + double result = SensorCentral.getInstance().getValue(Sensor.ETB_CONTROL_QUALITY); + MessagesCentral.getInstance().postMessage(EtbMonteCarloSequence.class, stats + ":result:" + result); + if (counter == LIMIT) { + MessagesCentral.getInstance().postMessage(EtbTestSequence.class, "ETB MC sequence done!"); + return; + } + counter++; + MessagesCentral.getInstance().postMessage(EtbTestSequence.class, "Starting " + counter + " of " + LIMIT); + runRandomCycle(); + } + }); + firstStep.execute(executor); + } + + public JButton getButton() { + return button; + } +} 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 f1a6218e8a..105f4333c0 100644 --- a/java_console/ui/src/com/rusefi/ui/widgets/EtbTestSequence.java +++ b/java_console/ui/src/com/rusefi/ui/widgets/EtbTestSequence.java @@ -6,6 +6,7 @@ import com.rusefi.core.MessagesCentral; import com.rusefi.core.Sensor; import com.rusefi.core.SensorCentral; import com.rusefi.io.CommandQueue; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.concurrent.Executors; @@ -26,14 +27,18 @@ import java.util.concurrent.TimeUnit; * @see TimeBasedBuffer */ public class EtbTestSequence { - private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - private boolean isStarted; + protected static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - protected final ClosedLoopControlQualityMetric metric = new ClosedLoopControlQualityMetric( - SensorCentral.getInstance().getValueSource(Sensor.PPS), - SensorCentral.getInstance().getValueSource(Sensor.TPS), - Sensor.ETB_CONTROL_QUALITY - ); + protected final static ClosedLoopControlQualityMetric metric = createMetric(); + + @NotNull + protected static ClosedLoopControlQualityMetric createMetric() { + return new ClosedLoopControlQualityMetric( + SensorCentral.getInstance().getValueSource(Sensor.PPS), + SensorCentral.getInstance().getValueSource(Sensor.TPS), + Sensor.ETB_CONTROL_QUALITY + ); + } private final static long SECOND = 1000; @@ -42,7 +47,11 @@ public class EtbTestSequence { private SequenceStep FIRST_STEP = new EtbTarget(10 * SECOND, 4 /*position*/); { - FIRST_STEP.add(new SequenceStep(SECOND) { + addSequence(FIRST_STEP); + } + + protected static SequenceStep addSequence(SequenceStep first_step) { + return first_step.addNext(new SequenceStep(SECOND) { @Override protected void doJob() { metric.reset(); @@ -56,24 +65,38 @@ public class EtbTestSequence { .addNext(5 * SECOND, 2 /*position*/) .addNext(5 * SECOND, 0 /*position*/) .addNext(5 * SECOND, 10 /*position*/) - .addNext(10 * SECOND, 6 /*position*/) - .addNext(10 * SECOND, 30 /*position*/) - .addNext(10 * SECOND, 50 /*position*/) - .addNext(10 * SECOND, 70 /*position*/) - .addNext(10 * SECOND, 100 /*position*/) - .addNext(10 * SECOND, 50 /*position*/) - .addNext(10 * SECOND, 70 /*position*/) - .addNext(10 * SECOND, 4 /*position*/) - .addNext(10 * SECOND, 0 /*position*/) - ; + .addNext(3 * SECOND, 0 /*position*/) + .addNext(1 * SECOND, 6 /*position*/) + .addNext(1 * SECOND, 8 /*position*/) + .addNext(1 * SECOND, 6 /*position*/) + .addNext(1 * SECOND, 4 /*position*/) + .addNext(1 * SECOND, 2 /*position*/) + .addNext(1 * SECOND, 0 /*position*/) + .addNext(1 * SECOND, 10 /*position*/) + .addNext(3 * SECOND, 7 /*position*/) + .addNext(3 * SECOND, 6 /*position*/) + .addNext(3 * SECOND, 5 /*position*/) + .addNext(3 * SECOND, 4 /*position*/) + .addNext(3 * SECOND, 3 /*position*/) + .addNext(3 * SECOND, 2 /*position*/) + .addNext(3 * SECOND, 1 /*position*/) + .addNext(3 * SECOND, 0 /*position*/) +// .addNext(10 * SECOND, 6 /*position*/) +// .addNext(10 * SECOND, 30 /*position*/) +// .addNext(10 * SECOND, 50 /*position*/) +// .addNext(10 * SECOND, 70 /*position*/) +// .addNext(10 * SECOND, 100 /*position*/) +// .addNext(10 * SECOND, 50 /*position*/) +// .addNext(10 * SECOND, 70 /*position*/) +// .addNext(10 * SECOND, 4 /*position*/) +// .addNext(10 * SECOND, 0 /*position*/) + ; } public EtbTestSequence() { button.addActionListener(e -> { - if (!isStarted) { - metric.start(/* buffer size: */1000, /*period, ms: */ 100); - isStarted = true; - } + // 3000 data points at 10Hz should be 300 seconds worth of data + metric.start(/* buffer size: */3000, /*period, ms: */ 100); FIRST_STEP.execute(executor); }); } @@ -93,7 +116,7 @@ public class EtbTestSequence { public void execute(ScheduledExecutorService executor) { doJob(); if (next != null) { - FileLog.MAIN.logLine("Scheduling " + next); + FileLog.MAIN.logLine("Scheduling " + next + " with " + duration + "ms delay"); executor.schedule(() -> next.execute(executor), duration, TimeUnit.MILLISECONDS); } else { MessagesCentral.getInstance().postMessage(EtbTestSequence.class, "ETB test sequence done!"); @@ -103,10 +126,10 @@ public class EtbTestSequence { protected abstract void doJob(); public SequenceStep addNext(long duration, double position) { - return add(new EtbTarget(duration, position)); + return addNext(new EtbTarget(duration, position)); } - private SequenceStep add(SequenceStep step) { + public SequenceStep addNext(SequenceStep step) { next = step; return next; }