ETB quality instrumentation #494
This commit is contained in:
parent
7e7261d2cc
commit
d9c31bd6bd
|
@ -0,0 +1,34 @@
|
||||||
|
package com.rusefi;
|
||||||
|
|
||||||
|
import com.rusefi.core.Sensor;
|
||||||
|
import com.rusefi.ui.GaugesGridElement;
|
||||||
|
import com.rusefi.ui.etb.CalibrationPanel;
|
||||||
|
import com.rusefi.ui.etb.CommandsPanel;
|
||||||
|
import com.rusefi.ui.util.UiUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls related to Electronic Throttle Body
|
||||||
|
*
|
||||||
|
* (c) Andrey Belomutskiy 2013-2019
|
||||||
|
*/
|
||||||
|
public class ETBPane {
|
||||||
|
private final JPanel content = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
|
public ETBPane() {
|
||||||
|
JPanel centerPanel = new JPanel(new GridLayout(2, 1));
|
||||||
|
centerPanel.add(GaugesGridElement.create(Sensor.PPS));
|
||||||
|
centerPanel.add(GaugesGridElement.create(Sensor.TPS));
|
||||||
|
|
||||||
|
content.add(new CommandsPanel().getContent(), BorderLayout.WEST);
|
||||||
|
content.add(centerPanel, BorderLayout.CENTER);
|
||||||
|
content.add(new CalibrationPanel().getContent(), BorderLayout.EAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.rusefi.ui.widgets;
|
package com.rusefi.etb;
|
||||||
|
|
||||||
import com.rusefi.CyclicBuffer;
|
import com.rusefi.CyclicBuffer;
|
||||||
import com.rusefi.DataBuffer;
|
import com.rusefi.DataBuffer;
|
||||||
|
@ -63,7 +63,7 @@ public class ClosedLoopControlQualityMetric {
|
||||||
errorsBuffer.clear();
|
errorsBuffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized double getStandardDeviation() {
|
public synchronized double getStandardDeviation() {
|
||||||
return DataBuffer.getStandardDeviation(errorsBuffer.getValues());
|
return DataBuffer.getStandardDeviation(errorsBuffer.getValues());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.rusefi.etb;
|
||||||
|
|
||||||
|
import com.rusefi.io.CommandQueue;
|
||||||
|
|
||||||
|
public class EtbTarget extends TestSequenceStep {
|
||||||
|
/**
|
||||||
|
* 0-100 percent open
|
||||||
|
*/
|
||||||
|
private final double position;
|
||||||
|
private final Runnable onEachStep;
|
||||||
|
|
||||||
|
public EtbTarget(long duration, double position, Runnable onEachStep) {
|
||||||
|
super(duration);
|
||||||
|
this.position = position;
|
||||||
|
this.onEachStep = onEachStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doJob() {
|
||||||
|
CommandQueue.getInstance().write("set mock_pedal_position " + position);
|
||||||
|
if (onEachStep != null)
|
||||||
|
onEachStep.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "EtbTarget{" +
|
||||||
|
"duration=" + duration +
|
||||||
|
", position=" + position +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.rusefi.etb;
|
||||||
|
|
||||||
|
import com.rusefi.core.Sensor;
|
||||||
|
import com.rusefi.core.SensorCentral;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import static com.rusefi.Timeouts.SECOND;
|
||||||
|
|
||||||
|
public class StandardTestSequence {
|
||||||
|
public 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestSequenceStep addSequence(TestSequenceStep first_step, Runnable onEachStep) {
|
||||||
|
TestSequenceStep secondStep = new TestSequenceStep(SECOND) {
|
||||||
|
@Override
|
||||||
|
protected void doJob() {
|
||||||
|
metric.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
TestSequenceStep result = first_step.addNext(secondStep)
|
||||||
|
.addNext(10 * SECOND, 4 /*position*/, onEachStep)
|
||||||
|
.addNext(5 * SECOND, 6, /*position*/onEachStep)
|
||||||
|
.addNext(5 * SECOND, 8, /*position*/onEachStep)
|
||||||
|
.addNext(5 * SECOND, 6, /*position*/onEachStep)
|
||||||
|
.addNext(5 * SECOND, 4, /*position*/onEachStep)
|
||||||
|
.addNext(5 * SECOND, 2, /*position*/onEachStep)
|
||||||
|
.addNext(5 * SECOND, 0, /*position*/onEachStep)
|
||||||
|
.addNext(5 * SECOND, 10, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 0, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 6, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 8, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 6, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 4, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 2, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 0, /*position*/onEachStep)
|
||||||
|
.addNext(1 * SECOND, 10, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 7, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 6, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 5, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 4, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 3, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 2, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 1, /*position*/onEachStep)
|
||||||
|
.addNext(3 * SECOND, 0, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 6, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 30, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 50, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 70, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 95, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 50, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 70, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 4, /*position*/onEachStep)
|
||||||
|
.addNext(10 * SECOND, 0, /*position*/onEachStep)
|
||||||
|
;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.rusefi.etb;
|
||||||
|
|
||||||
|
import com.rusefi.FileLog;
|
||||||
|
import com.rusefi.core.MessagesCentral;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public abstract class TestSequenceStep {
|
||||||
|
protected final long duration;
|
||||||
|
private TestSequenceStep next;
|
||||||
|
|
||||||
|
public TestSequenceStep(long duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(ScheduledExecutorService executor) {
|
||||||
|
doJob();
|
||||||
|
if (next != null) {
|
||||||
|
FileLog.MAIN.logLine("Scheduling " + next + " with " + duration + "ms delay");
|
||||||
|
executor.schedule(() -> next.execute(executor), duration, TimeUnit.MILLISECONDS);
|
||||||
|
} else {
|
||||||
|
MessagesCentral.getInstance().postMessage(TestSequenceStep.class, "ETB test sequence done!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doJob();
|
||||||
|
|
||||||
|
public TestSequenceStep addNext(long duration, double position, Runnable onEachStep) {
|
||||||
|
return addNext(new EtbTarget(duration, position, onEachStep));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestSequenceStep addNext(TestSequenceStep step) {
|
||||||
|
next = step;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,11 +27,11 @@ public class GaugesGridElement {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GaugesGridElement create(Sensor sensor) {
|
public static JComponent create(Sensor sensor) {
|
||||||
return new GaugesGridElement(new Node()).create(sensor);
|
return new GaugesGridElement(new Node()).createGauge(sensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component createLiveBarElement(final Sensor defaultSensor) {
|
private JComponent createLiveBarElement(final Sensor defaultSensor) {
|
||||||
wrapper.setLayout(new GridLayout(2, 1));
|
wrapper.setLayout(new GridLayout(2, 1));
|
||||||
|
|
||||||
JMenuItem switchToGauge = new JMenuItem("Switch to Gauge Mode");
|
JMenuItem switchToGauge = new JMenuItem("Switch to Gauge Mode");
|
||||||
|
@ -50,7 +50,7 @@ public class GaugesGridElement {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component createGauge(final Sensor sensor) {
|
private JComponent createGauge(final Sensor sensor) {
|
||||||
SensorGauge.GaugeChangeListener gaugeChangeListener = new SensorGauge.GaugeChangeListener() {
|
SensorGauge.GaugeChangeListener gaugeChangeListener = new SensorGauge.GaugeChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSensorChange(Sensor sensor) {
|
public void onSensorChange(Sensor sensor) {
|
||||||
|
@ -75,7 +75,7 @@ public class GaugesGridElement {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Component read(final Node config, Sensor defaultSensor) {
|
public static JComponent read(final Node config, Sensor defaultSensor) {
|
||||||
|
|
||||||
if (config.getBoolProperty(IS_LIVE_GRAPH)) {
|
if (config.getBoolProperty(IS_LIVE_GRAPH)) {
|
||||||
return new GaugesGridElement(config).createLiveBarElement(defaultSensor);
|
return new GaugesGridElement(config).createLiveBarElement(defaultSensor);
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.rusefi.ui.etb;
|
||||||
|
|
||||||
|
import org.putgemin.VerticalFlowLayout;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class CalibrationPanel {
|
||||||
|
private final JPanel content = new JPanel(new VerticalFlowLayout());
|
||||||
|
|
||||||
|
public CalibrationPanel() {
|
||||||
|
content.setBorder(BorderFactory.createTitledBorder("Calibration"));
|
||||||
|
content.add(new JButton("Grab TPS#1 fully closed"));
|
||||||
|
content.add(new JButton("Grab TPS#1 Wide Open"));
|
||||||
|
|
||||||
|
content.add(new JButton("Grab Pedal Up"));
|
||||||
|
content.add(new JButton("Grab Pedal Down"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.rusefi.ui.etb;
|
||||||
|
|
||||||
|
import com.rusefi.ui.util.UiUtils;
|
||||||
|
import org.putgemin.VerticalFlowLayout;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class CommandsPanel {
|
||||||
|
private final JPanel content = new JPanel(new VerticalFlowLayout());
|
||||||
|
|
||||||
|
public CommandsPanel() {
|
||||||
|
|
||||||
|
|
||||||
|
JPanel testParameters = new JPanel(new VerticalFlowLayout());
|
||||||
|
testParameters.setBorder(BorderFactory.createTitledBorder("Try PID settings"));
|
||||||
|
EtbTestSequence etbTestSequence = new EtbTestSequence();
|
||||||
|
testParameters.add(UiUtils.wrap(etbTestSequence.getButton()));
|
||||||
|
testParameters.add(etbTestSequence.getResult());
|
||||||
|
testParameters.add(new JLabel("To change setting use following commands:"));
|
||||||
|
testParameters.add(new JLabel("set etb_p X"));
|
||||||
|
testParameters.add(new JLabel("set etb_i X"));
|
||||||
|
testParameters.add(new JLabel("set etb_d X"));
|
||||||
|
testParameters.add(new JLabel("set etb_o X"));
|
||||||
|
testParameters.add(new JLabel("For example:"));
|
||||||
|
testParameters.add(new JLabel("set etb_p 1.1"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
content.setBorder(BorderFactory.createTitledBorder("Commands"));
|
||||||
|
|
||||||
|
content.add(testParameters);
|
||||||
|
content.add(UiUtils.wrap(new EtbMonteCarloSequence().getButton()));
|
||||||
|
content.add(UiUtils.wrap(new MagicSpotsFinder().getButton()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
package com.rusefi.ui.widgets;
|
package com.rusefi.ui.etb;
|
||||||
|
|
||||||
import com.rusefi.core.MessagesCentral;
|
import com.rusefi.core.MessagesCentral;
|
||||||
import com.rusefi.core.Sensor;
|
import com.rusefi.core.Sensor;
|
||||||
import com.rusefi.core.SensorCentral;
|
import com.rusefi.core.SensorCentral;
|
||||||
|
import com.rusefi.etb.EtbTarget;
|
||||||
|
import com.rusefi.etb.StandardTestSequence;
|
||||||
|
import com.rusefi.etb.TestSequenceStep;
|
||||||
import com.rusefi.io.CommandQueue;
|
import com.rusefi.io.CommandQueue;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -11,7 +14,7 @@ import java.util.Random;
|
||||||
|
|
||||||
import static com.rusefi.SensorLogger.getSecondsSinceFileStart;
|
import static com.rusefi.SensorLogger.getSecondsSinceFileStart;
|
||||||
import static com.rusefi.Timeouts.SECOND;
|
import static com.rusefi.Timeouts.SECOND;
|
||||||
import static com.rusefi.ui.widgets.EtbTestSequence.*;
|
import static com.rusefi.ui.etb.EtbTestSequence.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 3/2/2019
|
* 3/2/2019
|
||||||
|
@ -28,7 +31,7 @@ public class EtbMonteCarloSequence {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
// 3000 data points at 10Hz should be 300 seconds worth of data
|
// 3000 data points at 10Hz should be 300 seconds worth of data
|
||||||
metric.start(/* buffer size: */3000, /*period, ms: */ 100);
|
StandardTestSequence.metric.start(/* buffer size: */3000, /*period, ms: */ 100);
|
||||||
|
|
||||||
executor.execute(this::runRandomCycle);
|
executor.execute(this::runRandomCycle);
|
||||||
});
|
});
|
||||||
|
@ -50,9 +53,9 @@ public class EtbMonteCarloSequence {
|
||||||
CommandQueue.getInstance().write("set etb_i " + iFactor);
|
CommandQueue.getInstance().write("set etb_i " + iFactor);
|
||||||
CommandQueue.getInstance().write("set etb_d " + dFactor);
|
CommandQueue.getInstance().write("set etb_d " + dFactor);
|
||||||
|
|
||||||
SequenceStep firstStep = new EtbTarget(10 * SECOND, 4 /*position*/);
|
TestSequenceStep firstStep = new EtbTarget(10 * SECOND, 4, null);
|
||||||
SequenceStep last = addSequence(firstStep);
|
TestSequenceStep last = StandardTestSequence.addSequence(firstStep, null);
|
||||||
last.addNext(new SequenceStep(5 * SECOND) {
|
last.addNext(new TestSequenceStep(5 * SECOND) {
|
||||||
@Override
|
@Override
|
||||||
protected void doJob() {
|
protected void doJob() {
|
||||||
double result = SensorCentral.getInstance().getValue(Sensor.ETB_CONTROL_QUALITY);
|
double result = SensorCentral.getInstance().getValue(Sensor.ETB_CONTROL_QUALITY);
|
|
@ -0,0 +1,76 @@
|
||||||
|
package com.rusefi.ui.etb;
|
||||||
|
|
||||||
|
import com.rusefi.TimeBasedBuffer;
|
||||||
|
import com.rusefi.core.Sensor;
|
||||||
|
import com.rusefi.etb.EtbTarget;
|
||||||
|
import com.rusefi.etb.StandardTestSequence;
|
||||||
|
import com.rusefi.etb.TestSequenceStep;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static com.rusefi.Timeouts.SECOND;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here we initiate a sequence of commands which would change target electronic throttle position so that we can
|
||||||
|
* see how far the result would be how soon.
|
||||||
|
* <p>
|
||||||
|
* Error standard deviation is posted to {@link Sensor#ETB_CONTROL_QUALITY}
|
||||||
|
* <p>
|
||||||
|
* https://github.com/rusefi/rusefi/issues/494
|
||||||
|
* <p>
|
||||||
|
* 11/16/2017
|
||||||
|
* (c) Andrey Belomutskiy
|
||||||
|
*
|
||||||
|
* @see TimeBasedBuffer
|
||||||
|
*/
|
||||||
|
public class EtbTestSequence {
|
||||||
|
protected static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
private static final String BUTTON_TEXT = "Measure Quality Control";
|
||||||
|
|
||||||
|
private final JButton button = new JButton(BUTTON_TEXT);
|
||||||
|
private final JLabel result = new JLabel("Result: N/A");
|
||||||
|
|
||||||
|
public EtbTestSequence() {
|
||||||
|
button.addActionListener(e -> {
|
||||||
|
button.setEnabled(false);
|
||||||
|
// 3000 data points at 10Hz should be 300 seconds worth of data
|
||||||
|
StandardTestSequence.metric.start(/* buffer size: */3000, /*period, ms: */ 100);
|
||||||
|
|
||||||
|
AtomicInteger stepCounter = new AtomicInteger();
|
||||||
|
|
||||||
|
TestSequenceStep lastStep = new TestSequenceStep(SECOND) {
|
||||||
|
@Override
|
||||||
|
protected void doJob() {
|
||||||
|
button.setEnabled(true);
|
||||||
|
button.setText(BUTTON_TEXT);
|
||||||
|
double value = StandardTestSequence.metric.getStandardDeviation();
|
||||||
|
result.setText(String.format("Result: %.3f", value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Runnable onEachStep = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
SwingUtilities.invokeLater(() -> button.setText("Running " + stepCounter.incrementAndGet()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TestSequenceStep firstStep = new EtbTarget(10 * SECOND, 4, /*position*/onEachStep);
|
||||||
|
TestSequenceStep result = StandardTestSequence.addSequence(firstStep, onEachStep);
|
||||||
|
result.addNext(lastStep);
|
||||||
|
firstStep.execute(executor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getButton() {
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JLabel getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.rusefi.ui.widgets;
|
package com.rusefi.ui.etb;
|
||||||
|
|
||||||
import com.rusefi.core.MessagesCentral;
|
import com.rusefi.core.MessagesCentral;
|
||||||
import com.rusefi.core.Sensor;
|
import com.rusefi.core.Sensor;
|
||||||
|
@ -11,12 +11,16 @@ import java.awt.event.ActionEvent;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import static com.rusefi.Timeouts.SECOND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This tool finds interesting ETB duty cycles like the value when in starts to open or the value
|
||||||
|
* when it's completely open
|
||||||
|
* <p>
|
||||||
* (c) Andrey Belomutskiy
|
* (c) Andrey Belomutskiy
|
||||||
* 10/21/2018
|
* 10/21/2018
|
||||||
*/
|
*/
|
||||||
public class EtbResearch {
|
public class MagicSpotsFinder {
|
||||||
private static final int SECOND = 1000;
|
|
||||||
private static final long SLEEP = SECOND;
|
private static final long SLEEP = SECOND;
|
||||||
// how much do we want to change duty cycle on each iteration?
|
// how much do we want to change duty cycle on each iteration?
|
||||||
private static final double DUTY_CYCLE_STEP = 0.5;
|
private static final double DUTY_CYCLE_STEP = 0.5;
|
||||||
|
@ -27,7 +31,7 @@ public class EtbResearch {
|
||||||
// private boolean isStarted;
|
// private boolean isStarted;
|
||||||
|
|
||||||
|
|
||||||
State state;
|
private State state;
|
||||||
private double currentValue;
|
private double currentValue;
|
||||||
/**
|
/**
|
||||||
* here we record at which duty cycle ETB would start moving
|
* here we record at which duty cycle ETB would start moving
|
||||||
|
@ -149,7 +153,7 @@ public class EtbResearch {
|
||||||
backToZeroValue = 0;
|
backToZeroValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EtbResearch() {
|
public MagicSpotsFinder() {
|
||||||
button.addActionListener(new AbstractAction() {
|
button.addActionListener(new AbstractAction() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
|
@ -1,159 +0,0 @@
|
||||||
package com.rusefi.ui.widgets;
|
|
||||||
|
|
||||||
import com.rusefi.FileLog;
|
|
||||||
import com.rusefi.TimeBasedBuffer;
|
|
||||||
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;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Here we initiate a sequence of commands which would change target electronic throttle position so that we can
|
|
||||||
* see how far the result would be how soon.
|
|
||||||
* <p>
|
|
||||||
* Error standard deviation is posted to {@link Sensor#ETB_CONTROL_QUALITY}
|
|
||||||
* <p>
|
|
||||||
* https://github.com/rusefi/rusefi/issues/494
|
|
||||||
* <p>
|
|
||||||
* 11/16/2017
|
|
||||||
* (c) Andrey Belomutskiy
|
|
||||||
*
|
|
||||||
* @see TimeBasedBuffer
|
|
||||||
*/
|
|
||||||
public class EtbTestSequence {
|
|
||||||
protected static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
private final JButton button = new JButton("ETB Test");
|
|
||||||
|
|
||||||
|
|
||||||
protected static SequenceStep addSequence(SequenceStep first_step) {
|
|
||||||
return first_step.addNext(new SequenceStep(SECOND) {
|
|
||||||
@Override
|
|
||||||
protected void doJob() {
|
|
||||||
metric.reset();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.addNext(10 * SECOND, 4 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 6 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 8 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 6 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 4 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 2 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 0 /*position*/)
|
|
||||||
.addNext(5 * SECOND, 10 /*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, 95 /*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 -> {
|
|
||||||
// 3000 data points at 10Hz should be 300 seconds worth of data
|
|
||||||
metric.start(/* buffer size: */3000, /*period, ms: */ 100);
|
|
||||||
|
|
||||||
SequenceStep firstStep = new EtbTarget(10 * SECOND, 4 /*position*/);
|
|
||||||
addSequence(firstStep);
|
|
||||||
firstStep.execute(executor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public JButton getButton() {
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
static abstract class SequenceStep {
|
|
||||||
final long duration;
|
|
||||||
SequenceStep next;
|
|
||||||
|
|
||||||
public SequenceStep(long duration) {
|
|
||||||
this.duration = duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute(ScheduledExecutorService executor) {
|
|
||||||
doJob();
|
|
||||||
if (next != null) {
|
|
||||||
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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void doJob();
|
|
||||||
|
|
||||||
public SequenceStep addNext(long duration, double position) {
|
|
||||||
return addNext(new EtbTarget(duration, position));
|
|
||||||
}
|
|
||||||
|
|
||||||
public SequenceStep addNext(SequenceStep step) {
|
|
||||||
next = step;
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class EtbTarget extends SequenceStep {
|
|
||||||
/**
|
|
||||||
* 0-100 percent open
|
|
||||||
*/
|
|
||||||
final double position;
|
|
||||||
|
|
||||||
public EtbTarget(long duration, double position) {
|
|
||||||
super(duration);
|
|
||||||
this.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doJob() {
|
|
||||||
CommandQueue.getInstance().write("set mock_pedal_position " + position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "EtbTarget{" +
|
|
||||||
"duration=" + duration +
|
|
||||||
", position=" + position +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue