ETB quality instrumentation #494

This commit is contained in:
rusEfi 2019-06-26 22:25:30 -04:00
parent 5bb016ef59
commit a92702dd54
6 changed files with 85 additions and 16 deletions

View File

@ -30,6 +30,10 @@ public class CyclicBuffer implements DataBuffer {
pointer = 0;
}
public int getPointer() {
return pointer;
}
public int getSize() {
return size;
}
@ -44,6 +48,10 @@ public class CyclicBuffer implements DataBuffer {
}
public double get(int i) {
return values[i];
if (size < 1)
throw new IllegalStateException("Size " + size);
while (i < 0)
i += size;
return values[i % size];
}
}

View File

@ -8,6 +8,7 @@ import com.rusefi.core.SensorCentral;
import com.rusefi.core.SensorStats;
import com.rusefi.core.ValueSource;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -24,6 +25,7 @@ import java.util.concurrent.TimeUnit;
*/
public class ClosedLoopControlQualityMetric {
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(ClosedLoopControlQualityMetric.class.getSimpleName()));
private final int delayDepth;
private final ValueSource target;
private final ValueSource result;
@ -35,15 +37,18 @@ public class ClosedLoopControlQualityMetric {
* GuardedBy(this)
*/
private DataBuffer errorsBuffer;
private CyclicBuffer targetBuffer;
/**
* @param target what value are we trying to achieve
* @param result what value do we actually have
* @param delayDepth
* @param target what value are we trying to achieve
* @param result what value do we actually have
*/
public ClosedLoopControlQualityMetric(ValueSource target, ValueSource result, Sensor destination) {
public ClosedLoopControlQualityMetric(ValueSource target, ValueSource result, Sensor destination, int delayDepth) {
this.target = target;
this.result = result;
this.destination = destination;
this.delayDepth = delayDepth;
}
public void start(int bufferSize, int periodMs) {
@ -51,14 +56,31 @@ public class ClosedLoopControlQualityMetric {
return;
isStarted = true;
errorsBuffer = new CyclicBuffer(bufferSize);
create(bufferSize);
executor.scheduleAtFixedRate(() -> {
rememberCurrentError(target.getValue() - result.getValue());
add();
SensorCentral.getInstance().setValue(getStandardDeviation(), destination);
}, 0, periodMs, TimeUnit.MILLISECONDS);
}
public void add() {
double targetValue = target.getValue();
double resultValue = result.getValue();
double error = Math.abs(targetValue - resultValue);
int pointer = targetBuffer.getPointer();
for (int i = 0; i < Math.min(delayDepth - 1, targetBuffer.getSize()); i++) {
double thisError = Math.abs(targetBuffer.get(pointer - i) - resultValue);
error = Math.min(error, thisError);
}
rememberCurrentError(error, targetValue);
}
public void create(int bufferSize) {
errorsBuffer = new CyclicBuffer(bufferSize);
targetBuffer = new CyclicBuffer(delayDepth);
}
public synchronized void reset() {
errorsBuffer.clear();
}
@ -67,7 +89,9 @@ public class ClosedLoopControlQualityMetric {
return DataBuffer.getStandardDeviation(errorsBuffer.getValues());
}
private synchronized void rememberCurrentError(double error) {
private synchronized void rememberCurrentError(double error, double targetValue) {
Objects.requireNonNull(errorsBuffer, "errorsBuffer");
errorsBuffer.add(error);
targetBuffer.add(targetValue);
}
}

View File

@ -5,6 +5,7 @@ import com.rusefi.core.SensorCentral;
import org.jetbrains.annotations.NotNull;
import static com.rusefi.Timeouts.SECOND;
import static com.rusefi.ui.etb.EtbTestSequence.PAST_DEPTH;
public class StandardTestSequence {
public final static ClosedLoopControlQualityMetric metric = createMetric();
@ -14,7 +15,8 @@ public class StandardTestSequence {
return new ClosedLoopControlQualityMetric(
SensorCentral.getInstance().getValueSource(Sensor.PPS),
SensorCentral.getInstance().getValueSource(Sensor.TPS),
Sensor.ETB_CONTROL_QUALITY
Sensor.ETB_CONTROL_QUALITY,
PAST_DEPTH
);
}

View File

@ -0,0 +1,33 @@
package com.rusefi.etb.test;
import com.rusefi.core.Sensor;
import com.rusefi.etb.ClosedLoopControlQualityMetric;
import org.junit.Test;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
public class ClosedLoopControlQualityMetricTest {
private static final double EPS = 0;
@Test
public void testPastDepth() {
AtomicInteger targetValue = new AtomicInteger();
AtomicInteger resultValue = new AtomicInteger();
ClosedLoopControlQualityMetric m = new ClosedLoopControlQualityMetric(
targetValue::doubleValue,
resultValue::doubleValue,
Sensor.ETB_CONTROL_QUALITY, 3);
m.create(1000);
m.add();
assertEquals(0, m.getStandardDeviation(), EPS);
targetValue.set(10);
// result same 0
m.add();
assertEquals(0, m.getStandardDeviation(), EPS);
}
}

View File

@ -26,14 +26,14 @@ import static com.rusefi.ui.etb.EtbTestSequence.*;
* (c) Andrey Belomutskiy
*/
public class EtbMonteCarloSequence {
private static final int TOTAL_CYCLES_COUNT = 300;
private static final int TOTAL_CYCLES_COUNT = 15;
private static final double DEFAULT_POSITION = 7;
private static final int CLT_THRESHOLD = 75;
private final JButton button = new JButton("ETB I feel lucky!");
private final static Random r = new Random();
private int counter;
private double bestResultSoFar = 75;
private double bestResultSoFar = 750;
public EtbMonteCarloSequence() {
button.addActionListener(e -> {
@ -44,8 +44,6 @@ public class EtbMonteCarloSequence {
public void run() {
CommandQueue.getInstance().write(CANCEL_DIRECT_DRIVE_COMMAND);
sleep(3 * SECOND);
int durationSeconds = 300;
int frequencyHz = 100;
// 30000 data points at 100Hz should be 300 seconds worth of data
StandardTestSequence.metric.start(/* buffer size: */durationSeconds * frequencyHz, /*period, ms: */ 1000 / frequencyHz);
@ -58,9 +56,9 @@ public class EtbMonteCarloSequence {
private void runRandomCycle() {
final int offset = 0;//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;
final double pFactor = 6 + counter * 2;// + (r.nextInt(300) / 100.0);
final double iFactor = 0;//r.nextInt(30) / 100.0;
final double dFactor = 0;//r.nextInt(30) / 100.0;
String stats = "mcstats:offset:" + offset +
":pFactor:" + pFactor +
":iFactor:" + iFactor +

View File

@ -28,6 +28,9 @@ import static com.rusefi.Timeouts.SECOND;
*/
public class EtbTestSequence {
protected static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
public static final int durationSeconds = 300;
public static final int frequencyHz = 100;
public static final int PAST_DEPTH = 200 / (1000 / frequencyHz);
private static final String BUTTON_TEXT = "Measure Control Quality";
@ -38,7 +41,8 @@ public class 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);
StandardTestSequence.metric.start(/* buffer size: */durationSeconds * frequencyHz,
/*period, ms: */ 1000 / frequencyHz);
AtomicInteger stepCounter = new AtomicInteger();
AtomicInteger totalSteps = new AtomicInteger();