only:dead
This commit is contained in:
parent
c925eedf65
commit
349f2fe51e
|
@ -1,48 +0,0 @@
|
|||
package com.rusefi;
|
||||
|
||||
import com.rusefi.models.MafValue;
|
||||
import com.rusefi.models.RpmValue;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 1/29/13
|
||||
*/
|
||||
public class ReportLine {
|
||||
private final int time;
|
||||
private final MafValue maf;
|
||||
private final RpmValue rpm;
|
||||
private final int wave;
|
||||
|
||||
public ReportLine(int time, MafValue maf, RpmValue rpm, int wave) {
|
||||
this.time = time;
|
||||
this.maf = maf;
|
||||
this.rpm = rpm;
|
||||
this.wave = wave;
|
||||
}
|
||||
|
||||
public int getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public MafValue getMaf() {
|
||||
return maf;
|
||||
}
|
||||
|
||||
public RpmValue getRpm() {
|
||||
return rpm;
|
||||
}
|
||||
|
||||
public int getWave() {
|
||||
return wave;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReportLine{" +
|
||||
"time=" + time +
|
||||
", maf=" + maf +
|
||||
", rpm=" + rpm +
|
||||
", wave=" + wave +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
import com.rusefi.config.Field;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 7/14/2015
|
||||
*/
|
||||
public class Array1D {
|
||||
private double[] values;
|
||||
|
||||
public Array1D(double[] values) {
|
||||
this.values = values;
|
||||
for (int i = 1; i < values.length; i++) {
|
||||
double prev = values[i - 1];
|
||||
double current = values[i];
|
||||
if (prev >= current)
|
||||
throw new IllegalStateException("Out of order at index " + i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Array1D create(Field field, int offset, int size) {
|
||||
double result[] = new double[size];
|
||||
|
||||
return new Array1D(result);
|
||||
}
|
||||
|
||||
public int findIndex(double v) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (v < values[i])
|
||||
return i - 1;
|
||||
}
|
||||
return values.length;
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
/**
|
||||
* type-safe engine load value
|
||||
*
|
||||
* @author Andrey Belomutskiy
|
||||
* 7/14/2015
|
||||
*/
|
||||
public class EngineLoad {
|
||||
private final double value;
|
||||
|
||||
public EngineLoad(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 1/29/13
|
||||
*/
|
||||
public interface Factory<K, V> {
|
||||
V create(K key);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 1/29/13
|
||||
*/
|
||||
public class MafValue {
|
||||
|
||||
private final int value;
|
||||
|
||||
public MafValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static MafValue valueOf(String value) {
|
||||
return new MafValue(Utils.parseIntWithReason(value, "MAF value"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Maf{" +
|
||||
value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
/**
|
||||
* Date: 3/24/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class Range {
|
||||
private final float min;
|
||||
private final float max;
|
||||
|
||||
public Range(double min, double max) {
|
||||
this((float) min, (float) max);
|
||||
}
|
||||
|
||||
public Range(float min, float max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public float getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public float getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return max - min;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
/**
|
||||
* Type-safe immutable RPM value
|
||||
*
|
||||
* @author Andrey Belomutskiy
|
||||
* 1/29/13
|
||||
*/
|
||||
public class RpmValue {
|
||||
private final int value;
|
||||
|
||||
public RpmValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static RpmValue valueOf(String value) {
|
||||
return new RpmValue(Integer.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Rpm{"
|
||||
+ value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,46 +1,10 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 1/29/13
|
||||
*/
|
||||
public class Utils {
|
||||
// i do not want to deal with overflow so no MAX_VALUE for me
|
||||
private static final int LARGE_VALUE = 10000000;
|
||||
|
||||
/**
|
||||
* finds a key in the map which is closest to the specified element
|
||||
*/
|
||||
public static int findClosest(TreeMap<Integer, ?> map, int value) {
|
||||
SortedMap<Integer, ?> head = map.headMap(value, true);
|
||||
SortedMap<Integer, ?> tail = map.tailMap(value, true);
|
||||
if (head.isEmpty() && tail.isEmpty())
|
||||
throw new IllegalStateException("Empty map? " + value);
|
||||
|
||||
int fromHead = head.isEmpty() ? LARGE_VALUE : head.lastKey();
|
||||
int fromTail = tail.isEmpty() ? LARGE_VALUE : tail.firstKey();
|
||||
|
||||
int headDiff = Math.abs(value - fromHead);
|
||||
int tailDiff = Math.abs(value - fromTail);
|
||||
return headDiff < tailDiff ? fromHead : fromTail;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets an element from the map. if no such element - new one is created using the factory
|
||||
*/
|
||||
public static <K, V> V getOrCreate(Map<K, V> map, K key, Factory<K, V> factory) {
|
||||
V result = map.get(key);
|
||||
if (result != null)
|
||||
return result;
|
||||
result = factory.create(key);
|
||||
map.put(key, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int parseIntWithReason(String number, String reason) {
|
||||
try {
|
||||
return Integer.parseInt(number);
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package com.rusefi.trigger;
|
||||
|
||||
/**
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
* 1/18/2015
|
||||
*/
|
||||
public class MiataNA implements TriggerShape {
|
||||
@Override
|
||||
public int getTotalToothCount() {
|
||||
return 6;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.rusefi.trigger;
|
||||
|
||||
/**
|
||||
* http://rusefi.com/wiki/index.php?title=Manual:Software:Trigger
|
||||
*
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
* 1/18/2015
|
||||
*/
|
||||
public interface TriggerShape {
|
||||
int getTotalToothCount();
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package com.rusefi.trigger;
|
||||
|
||||
/**
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
* 1/18/2015
|
||||
*/
|
||||
public class TriggerShapeHolder {
|
||||
public static TriggerShape CURRENT = new MiataNA();
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.rusefi.models.test;
|
||||
|
||||
import com.rusefi.models.Array1D;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 7/14/2015
|
||||
*/
|
||||
public class Array1DTest {
|
||||
@Test
|
||||
public void testArrayValidation() {
|
||||
try {
|
||||
new Array1D(new double[] {3, 1});
|
||||
} catch (Throwable e) {
|
||||
// expected behaviour
|
||||
}
|
||||
new Array1D(new double[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindIndex() {
|
||||
Array1D array = new Array1D(new double[] {1 , 2, 3, 4});
|
||||
|
||||
assertEquals(-1, array.findIndex(0));
|
||||
assertEquals(0, array.findIndex(1));
|
||||
assertEquals(0, array.findIndex(1.5));
|
||||
assertEquals(4, array.findIndex(15));
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package com.rusefi.models.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static com.rusefi.models.Utils.findClosest;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 1/29/13
|
||||
*/
|
||||
public class UtilTest {
|
||||
@Test
|
||||
public void testClosest() {
|
||||
TreeMap<Integer, Object> map = new TreeMap<>();
|
||||
map.put(0, "0");
|
||||
map.put(1, "1");
|
||||
map.put(10, "10");
|
||||
map.put(11, "11");
|
||||
|
||||
assertEquals(0, findClosest(map, -1));
|
||||
assertEquals(0, findClosest(map, 0));
|
||||
assertEquals(1, findClosest(map, 1));
|
||||
assertEquals(1, findClosest(map, 3));
|
||||
assertEquals(10, findClosest(map, 10));
|
||||
}
|
||||
}
|
|
@ -1,324 +0,0 @@
|
|||
package com.rusefi;
|
||||
|
||||
import com.rusefi.core.MessagesCentral;
|
||||
import com.rusefi.core.Sensor;
|
||||
import com.rusefi.core.SensorCentral;
|
||||
import com.rusefi.file.TableGenerator;
|
||||
import com.rusefi.models.Point3D;
|
||||
import com.rusefi.models.Range;
|
||||
import com.rusefi.models.XYData;
|
||||
//import com.rusefi.ui.ChartHelper;
|
||||
import com.rusefi.ui.RpmModel;
|
||||
//import com.rusefi.ui.widgets.PotCommand;
|
||||
import com.rusefi.ui.widgets.RpmCommand;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* Date: 3/24/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
/*
|
||||
public class EcuStimulator {
|
||||
private static final String DELIMITER = ",";
|
||||
private static final long SLEEP_TIME = 300;
|
||||
private static final double EPS = 0.001;
|
||||
|
||||
public boolean isDisplayingFuel = true;
|
||||
|
||||
private static final int MEASURES = 7;
|
||||
// private static final String C_FILE_NAME = "advance_map.c";
|
||||
// private static final String C_PREFIX = "ad_";
|
||||
|
||||
private static final String C_PREFIX = "fuel_";
|
||||
|
||||
public static Range RPM_RANGE = new Range(0, StimulationInputs.DEFAULT_RPM_MAX); // x-coord
|
||||
private StimulationInputs inputs = new StimulationInputs(this);
|
||||
//
|
||||
private XYData data = new XYData();
|
||||
private DefaultSurfaceModel model = ChartHelper.createDefaultSurfaceModel(data, RPM_RANGE, new Range(1, 5));
|
||||
|
||||
private final JPanel content = new JPanel(new BorderLayout());
|
||||
|
||||
private static EcuStimulator instance = new EcuStimulator();
|
||||
|
||||
private final JLabel statusLabel = new JLabel();
|
||||
|
||||
private EcuStimulator() {
|
||||
JPanel panel = ChartHelper.create3DControl(data, model, isDisplayingFuel ? "Fuel Table" : "Timing");
|
||||
content.add(statusLabel, BorderLayout.NORTH);
|
||||
content.add(panel, BorderLayout.CENTER);
|
||||
content.add(inputs.getContent(), BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
public static EcuStimulator getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public JPanel getPanel() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void buildTable() {
|
||||
data.clear();
|
||||
|
||||
// setPotVoltage(2.2, Sensor.MAF);
|
||||
// if (1 == 1)
|
||||
// return;
|
||||
|
||||
String csvFileName = "table_" + inputs.getRpmStep() + "_" + inputs.getEngineLoadStep() + FileLog.getDate() + ".csv";
|
||||
FileLog.MAIN.logLine("Wring to " + csvFileName);
|
||||
|
||||
final BufferedWriter csv;
|
||||
try {
|
||||
csv = new BufferedWriter(new FileWriter(csvFileName));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
ResultListener listener = new ResultListener() {
|
||||
@Override
|
||||
public void onResult(int rpm, double engineLoad, double advance, double dwell) {
|
||||
data.addPoint(new Point3D(rpm, engineLoad, isDisplayingFuel ? (float) dwell : (float) advance));
|
||||
model.plot().execute();
|
||||
|
||||
String msg = putValue("rpm", rpm) +
|
||||
putValue("engine_load", engineLoad) +
|
||||
putValue("advance", advance) +
|
||||
putValue("dwell", dwell);
|
||||
MessagesCentral.getInstance().postMessage(EcuStimulator.class, msg);
|
||||
|
||||
try {
|
||||
csv.write(msg + "\r\n");
|
||||
csv.flush();
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ChartHelper.setYRange(new Range(inputs.getEngineLoadMin(), inputs.getEngineLoadMax()), model);
|
||||
|
||||
//buildTable(listener, DWELL_SENSOR);
|
||||
|
||||
try {
|
||||
csv.close();
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
TableGenerator.writeAsC(data, C_PREFIX, "map" + FileLog.getDate() + ".c");
|
||||
}
|
||||
|
||||
private void buildTable(ResultListener listener, Sensor dwellSensor) {
|
||||
for (double rpm = inputs.getRpmFrom(); rpm <= inputs.getRpmTo() + EPS; rpm += inputs.getRpmStep()) {
|
||||
for (double engineLoad = inputs.getEngineLoadMin(); engineLoad <= inputs.getEngineLoadMax() + EPS; engineLoad += inputs.getEngineLoadStep()) {
|
||||
for (int clt = inputs.getCltFrom(); clt <= inputs.getCltTo(); clt += 100) {
|
||||
testPoint((int) rpm, engineLoad, clt, listener, dwellSensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testPoint(int rpm, double engineLoad, int clt, ResultListener resultListener, Sensor dwellSensor) {
|
||||
//setPotVoltage(maf, Sensor.MAF);
|
||||
setPotVoltage(engineLoad, null);
|
||||
setRpm(rpm);
|
||||
/**
|
||||
* Let's give the firmware some time to react
|
||||
*/
|
||||
/*
|
||||
sleepRuntime(SLEEP_TIME);
|
||||
|
||||
statusLabel.setText("RPM " + rpm + ", el " + engineLoad + ", CLT " + clt);
|
||||
|
||||
/**
|
||||
* We are making a number of measurements and then we take the middle one
|
||||
*/
|
||||
/*
|
||||
MultipleMeasurements r = waitForMultipleResults(dwellSensor, null);
|
||||
List<Double> dwells = r.getDwells();
|
||||
List<Double> advances = r.getAdvances();
|
||||
|
||||
// sorting measurements, taking middle value
|
||||
Collections.sort(dwells);
|
||||
Collections.sort(advances);
|
||||
|
||||
double dwellDiff = Math.abs(dwells.get(0) - dwells.get(MEASURES - 1));
|
||||
if (dwellDiff > 1)
|
||||
System.out.println("dwells " + dwells);
|
||||
|
||||
double dwell = dwells.get(MEASURES / 2);
|
||||
double advance = advances.get(MEASURES / 2);
|
||||
|
||||
// if (dwell > 40)
|
||||
// throw new IllegalStateException("Unexpected value, how come? " + dwell);
|
||||
|
||||
log("Stimulator result: " + rpm + "@" + engineLoad + ": " + dwell + ", adv=" + advance);
|
||||
|
||||
// double dwell = Launcher.getAdcModel().getValue(Sensor.DWELL0);
|
||||
// double advance = Launcher.getAdcModel().getValue(Sensor.ADVANCE);
|
||||
|
||||
resultListener.onResult(rpm, engineLoad, (float) advance, dwell);
|
||||
}
|
||||
|
||||
private static void sleepRuntime(long sleepTime) {
|
||||
try {
|
||||
Thread.sleep(sleepTime);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static double getValue(Sensor sensor) {
|
||||
return SensorCentral.getInstance().getValue(sensor);
|
||||
}
|
||||
|
||||
private static void setRpm(int rpm) {
|
||||
int actual;
|
||||
int attempt = 0;
|
||||
do {
|
||||
RpmCommand.requestRpmChange(rpm, null);
|
||||
sleepRuntime(50);
|
||||
actual = RpmModel.getInstance().getValue();
|
||||
} while (attempt++ < 10 && Math.abs(rpm - actual) >= 100);
|
||||
log("Result: " + actual + " while setting " + rpm);
|
||||
}
|
||||
|
||||
public static void setPotVoltage(double targetVoltage, Sensor sensor) {
|
||||
if (sensor != null)
|
||||
log("Current targetVoltage: " + getValue(sensor) + ", setting " + targetVoltage);
|
||||
int attempt = 0;
|
||||
double vRef = getVRef();
|
||||
|
||||
int resistance = PotCommand.getPotResistance(targetVoltage, vRef);
|
||||
if (resistance <= 0) {
|
||||
log("Invalid resistance " + resistance + ". Invalid targetVoltage " + targetVoltage + "?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sensor == null) {
|
||||
PotCommand.requestPotChange(1, resistance);
|
||||
sleepRuntime(1000);
|
||||
} else {
|
||||
|
||||
double actual;
|
||||
do {
|
||||
PotCommand.requestPotChange(1, resistance);
|
||||
sleepRuntime(50);
|
||||
actual = getValue(sensor);
|
||||
log("Got: " + actual + " on attempt=" + attempt + " while setting " + targetVoltage + " for " + sensor);
|
||||
} while (attempt++ < 10 && Math.abs(targetVoltage - actual) > 0.2);
|
||||
log("Result: " + actual + " while setting " + targetVoltage);
|
||||
}
|
||||
}
|
||||
|
||||
private static double getVRef() {
|
||||
// todo: make this adjustable via the UI
|
||||
//double vRef = SensorCentral.getConfig().getValue(Sensor.VREF) * PotCommand.VOLTAGE_CORRECTION;
|
||||
return 4.7;
|
||||
}
|
||||
|
||||
private static void log(String message) {
|
||||
MessagesCentral.getInstance().postMessage(EcuStimulator.class, message);
|
||||
FileLog.MAIN.logLine(message);
|
||||
}
|
||||
|
||||
private static String putValue(String msg, double value) {
|
||||
return msg + DELIMITER + value + DELIMITER;
|
||||
}
|
||||
|
||||
private static String putValue(String msg, int value) {
|
||||
return msg + DELIMITER + value + DELIMITER;
|
||||
}
|
||||
|
||||
public JButton createButton() {
|
||||
final JButton button = new JButton("stimulate stock ECU");
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
buildTable();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
System.exit(-20);
|
||||
}
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
button.setText("Done");
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "Ecu Stimulator").start();
|
||||
}
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
public StimulationInputs getInputs() {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
interface ResultListener {
|
||||
void onResult(int rpm, double engineLoad, double advance, double dwell);
|
||||
}
|
||||
|
||||
public MultipleMeasurements waitForMultipleResults(final Sensor dwellSensor, final Sensor advanceSensor) {
|
||||
final MultipleMeasurements result = new MultipleMeasurements();
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(MEASURES);
|
||||
|
||||
/*
|
||||
EngineTimeListener listener = new EngineTimeListener() {
|
||||
@Override
|
||||
public void onTime(double time) {
|
||||
if (latch.getCount() == 0)
|
||||
return;
|
||||
double dwell = getValue(dwellSensor);
|
||||
double advance = getValue(advanceSensor);
|
||||
advance = Sensor.processAdvance(advance);
|
||||
result.dwells.add(dwell);
|
||||
result.advances.add(advance);
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
LinkManager.engineState.timeListeners.add(listener);
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
LinkManager.engineState.timeListeners.remove(listener);
|
||||
*/
|
||||
/*
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class MultipleMeasurements {
|
||||
private List<Double> dwells = new ArrayList<>(MEASURES);
|
||||
private List<Double> advances = new ArrayList<>(MEASURES);
|
||||
|
||||
public List<Double> getDwells() {
|
||||
return dwells;
|
||||
}
|
||||
|
||||
public List<Double> getAdvances() {
|
||||
return advances;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -1,155 +0,0 @@
|
|||
package com.rusefi;
|
||||
|
||||
import com.rusefi.models.Factory;
|
||||
import com.rusefi.models.MafValue;
|
||||
import com.rusefi.models.RpmValue;
|
||||
import com.rusefi.models.Utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Date: 1/29/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class ReportReader {
|
||||
private static final Pattern LINE_PATTERN = Pattern.compile("\\D*(\\d*);a0;(\\d*);a1;-1;rpm;(\\d*);wave;(\\d*).*");
|
||||
private static final int INVALID_RPM_DIFF = 200;
|
||||
|
||||
public static void main(String[] args) {
|
||||
//List<ReportLine> lines = read("unfiltered.txt");
|
||||
readMap("200ohm.txt");
|
||||
|
||||
}
|
||||
|
||||
public static TreeMap<Integer, TreeMap<Integer, ReportLine>> readMap(String filename) {
|
||||
if (!new File(filename).exists()) {
|
||||
FileLog.MAIN.logLine("Error: not found " + filename);
|
||||
return new TreeMap<>();
|
||||
}
|
||||
List<ReportLine> lines = read(filename);
|
||||
FileLog.MAIN.logLine("Got " + lines.size() + " lines");
|
||||
|
||||
lines = filter(Collections.unmodifiableList(lines));
|
||||
|
||||
findMinMax(lines);
|
||||
|
||||
return asMap(lines);
|
||||
}
|
||||
|
||||
private static TreeMap<Integer, TreeMap<Integer, ReportLine>> asMap(List<ReportLine> lines) {
|
||||
/**
|
||||
* map of maps by RPM. inner map is by MAF
|
||||
*/
|
||||
TreeMap<Integer, TreeMap<Integer, ReportLine>> rpm2mapByMaf = new TreeMap<>();
|
||||
for (ReportLine cur : lines) {
|
||||
int rpmKey = cur.getRpm().getValue();
|
||||
|
||||
// round to 100
|
||||
rpmKey -= (rpmKey % 100);
|
||||
|
||||
TreeMap<Integer, ReportLine> maf2line = Utils.getOrCreate(rpm2mapByMaf, rpmKey, new Factory<Integer, TreeMap<Integer, ReportLine>>() {
|
||||
public TreeMap<Integer, ReportLine> create(Integer key) {
|
||||
return new TreeMap<>();
|
||||
}
|
||||
});
|
||||
maf2line.put(cur.getMaf().getValue(), cur);
|
||||
}
|
||||
return rpm2mapByMaf;
|
||||
}
|
||||
|
||||
private static void findMinMax(List<ReportLine> lines) {
|
||||
int minMaf = 100000;
|
||||
int maxMaf = 0;
|
||||
|
||||
int minRpm = 100000;
|
||||
int maxRpm = 0;
|
||||
for (ReportLine cur : lines) {
|
||||
minMaf = Math.min(minMaf, cur.getMaf().getValue());
|
||||
maxMaf = Math.max(maxMaf, cur.getMaf().getValue());
|
||||
|
||||
minRpm = Math.min(minRpm, cur.getRpm().getValue());
|
||||
maxRpm = Math.max(maxRpm, cur.getRpm().getValue());
|
||||
}
|
||||
FileLog.MAIN.logLine("MAF range from " + minMaf + " to " + maxMaf);
|
||||
FileLog.MAIN.logLine("RPM range from " + minRpm + " to " + maxRpm);
|
||||
}
|
||||
|
||||
private static List<ReportLine> filter(List<ReportLine> lines) {
|
||||
List<ReportLine> result = new ArrayList<>();
|
||||
int maxValidDiff = 0;
|
||||
int originalCount = lines.size();
|
||||
int removedCount = 0;
|
||||
|
||||
result.add(lines.get(0));
|
||||
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
ReportLine prev = result.get(result.size() - 1);
|
||||
ReportLine cur = lines.get(i);
|
||||
|
||||
int rpmDiff = cur.getRpm().getValue() - prev.getRpm().getValue();
|
||||
int timeDiff = cur.getTime() - prev.getTime();
|
||||
|
||||
if (Math.abs(rpmDiff) > INVALID_RPM_DIFF) {
|
||||
FileLog.MAIN.logLine("Invalid diff: " + cur);
|
||||
removedCount++;
|
||||
continue;
|
||||
}
|
||||
result.add(cur);
|
||||
// maximum valid diff
|
||||
maxValidDiff = Math.max(maxValidDiff, Math.abs(rpmDiff));
|
||||
// System.out.println("current rpm: " + cur + ", rpm diff=" + rpmDiff + " td=" + timeDiff);
|
||||
// System.out.println("value," + cur.getRpm().getValue() + "," + cur.getMaf().getValue() + "," + cur.getWave());
|
||||
}
|
||||
double percent = 100.0 * removedCount / originalCount;
|
||||
FileLog.MAIN.logLine(removedCount + " out of " + originalCount + " record(s) removed. " + percent + "%");
|
||||
FileLog.MAIN.logLine("Max valid diff: " + maxValidDiff);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<ReportLine> read(String filename) {
|
||||
List<ReportLine> result = new LinkedList<>();
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(filename));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
//process each line in some way
|
||||
ReportLine rl = handleOneLine(line);
|
||||
if (rl != null)
|
||||
result.add(rl);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int prevMaf = -1;
|
||||
private static int prevRpm = -1;
|
||||
private static int prevWave = -1;
|
||||
|
||||
private static ReportLine handleOneLine(String line) {
|
||||
// System.out.println(line);
|
||||
Matcher m = LINE_PATTERN.matcher(line);
|
||||
if (m.matches()) {
|
||||
int time = Integer.parseInt(m.group(1));
|
||||
MafValue maf = MafValue.valueOf(m.group(2));
|
||||
RpmValue rpm = RpmValue.valueOf(m.group(3));
|
||||
int wave = Integer.parseInt(m.group(4));
|
||||
|
||||
if (prevMaf == maf.getValue() && prevRpm == rpm.getValue() && prevWave == wave) {
|
||||
// System.out.println("All the same...");
|
||||
return null;
|
||||
}
|
||||
|
||||
//System.out.println(time + " m=" + maf + " r=" + rpm + " w=" + wave);
|
||||
prevMaf = maf.getValue();
|
||||
prevRpm = rpm.getValue();
|
||||
prevWave = wave;
|
||||
return new ReportLine(time, maf, rpm, wave);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package com.rusefi.etb;
|
||||
|
||||
import com.rusefi.CyclicBuffer;
|
||||
import com.rusefi.DataBuffer;
|
||||
import com.rusefi.NamedThreadFactory;
|
||||
import com.rusefi.core.Sensor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* https://github.com/rusefi/rusefi/issues/494
|
||||
* <p>
|
||||
* https://en.wikipedia.org/wiki/Standard_deviation of error posted to specified sensor
|
||||
* <p>
|
||||
* 11/16/2017
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*
|
||||
* @see SensorStats
|
||||
*/
|
||||
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;
|
||||
private final Sensor destination;
|
||||
private boolean isStarted;
|
||||
|
||||
/**
|
||||
* Buffer of recent error measurements
|
||||
* GuardedBy(this)
|
||||
*/
|
||||
private DataBuffer errorsBuffer;
|
||||
private CyclicBuffer targetBuffer;
|
||||
|
||||
/**
|
||||
* @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, int delayDepth) {
|
||||
this.target = target;
|
||||
this.result = result;
|
||||
this.destination = destination;
|
||||
this.delayDepth = delayDepth;
|
||||
}
|
||||
|
||||
public void start(int bufferSize, int periodMs) {
|
||||
if (isStarted)
|
||||
return;
|
||||
isStarted = true;
|
||||
|
||||
create(bufferSize);
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
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();
|
||||
}
|
||||
|
||||
public synchronized double getStandardDeviation() {
|
||||
return DataBuffer.getStandardDeviation(errorsBuffer.getValues());
|
||||
}
|
||||
|
||||
private synchronized void rememberCurrentError(double error, double targetValue) {
|
||||
Objects.requireNonNull(errorsBuffer, "errorsBuffer");
|
||||
errorsBuffer.add(error);
|
||||
targetBuffer.add(targetValue);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package com.rusefi.file;
|
||||
|
||||
import com.rusefi.FileLog;
|
||||
import com.rusefi.models.XYData;
|
||||
|
||||
/**
|
||||
* 7/18/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class BaseMap {
|
||||
public static void main(String[] args) {
|
||||
loadData("a.csv", "maf", "af");
|
||||
}
|
||||
|
||||
public static XYData loadData(String filename, final String key, final String value) {
|
||||
FileLog.MAIN.logLine("Loading from " + filename);
|
||||
FileLog.MAIN.logLine("Loading " + key + ">" + value);
|
||||
final XYData data = new XYData();
|
||||
|
||||
/*
|
||||
EngineState.EngineStateListener listener = new EngineState.EngineStateListenerImpl() {
|
||||
Map<String, String> values = new HashMap<String, String>();
|
||||
|
||||
@Override
|
||||
public void onKeyValue(String key, String value) {
|
||||
values.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterLine(String fullLine) {
|
||||
if (values.containsKey("rpm") && values.containsKey(key)) {
|
||||
process(values);
|
||||
}
|
||||
values.clear();
|
||||
}
|
||||
|
||||
private void process(Map<String, String> values) {
|
||||
int rpm = (int) Double.parseDouble(values.get("rpm"));
|
||||
double k = Double.parseDouble(values.get(key));
|
||||
String valueString = values.get(value);
|
||||
if (valueString == null)
|
||||
throw new NullPointerException("No value for: " + value);
|
||||
float v = Float.parseFloat(valueString);
|
||||
|
||||
data.addPoint(new Point3D(rpm, k, v));
|
||||
}
|
||||
};
|
||||
EngineState engineState = new EngineState(listener);
|
||||
engineState.registerStringValueAction(EngineReport.ENGINE_CHART, new EngineState.ValueCallback<String>() {
|
||||
@Override
|
||||
public void onUpdate(String value) {
|
||||
}
|
||||
});
|
||||
FileUtils.readFile2(filename, engineState);
|
||||
//return AverageData.average(data, 8);
|
||||
*/
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package com.rusefi.file;
|
||||
|
||||
import com.rusefi.models.XYData;
|
||||
import com.rusefi.models.XYDataReader;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
* 3/27/13
|
||||
*/
|
||||
public class TableGenerator {
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
XYData data = XYDataReader.readFile("in.csv");
|
||||
|
||||
writeAsC(data, "ad_", "advance_map.c");
|
||||
}
|
||||
|
||||
public static void writeAsC(XYData data, String prefix, String fileName) {
|
||||
try {
|
||||
doWrite(data, prefix, fileName);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doWrite(XYData data, String prefix, String fileName) throws IOException {
|
||||
List<Double> rpms = new ArrayList<>(data.getXSet());
|
||||
BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
|
||||
out.write("#include \"thermistors.h\"\n\n\n");
|
||||
|
||||
// writeArray(rpms, out, prefix + "rpm");
|
||||
|
||||
List<Double> engineLoadValues = new ArrayList<>(data.getYAxis(rpms.get(0)).getYs());
|
||||
// writeArray(yArray, out, prefix + "maf");
|
||||
|
||||
out.write("static float " + prefix + "table[" + rpms.size() + "][" + engineLoadValues.size() + "] = {\n");
|
||||
|
||||
boolean isFirstEngineLoad = true;
|
||||
int indexX = 0;
|
||||
for (double engineLoad : engineLoadValues) {
|
||||
if (!isFirstEngineLoad)
|
||||
out.write(",\n");
|
||||
isFirstEngineLoad = false;
|
||||
|
||||
out.write("{");
|
||||
|
||||
int indexY = 0;
|
||||
for (double rpm : data.getXSet()) {
|
||||
if (indexY == 0)
|
||||
out.write("/*" + indexX + " engineLoad=" + engineLoadValues.get(indexX) + "*/");
|
||||
|
||||
if (indexY > 0)
|
||||
out.write(", ");
|
||||
|
||||
out.write("/*" + indexY + " " + rpms.get(indexY) + "*/" + data.getValue(rpm, engineLoad));
|
||||
indexY++;
|
||||
}
|
||||
out.write("}");
|
||||
indexX++;
|
||||
}
|
||||
out.write("\n};\n");
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static void writeArray(List<Double> rpms, BufferedWriter out, String title) throws IOException {
|
||||
out.write("#define " + title.toUpperCase() + "_COUNT " + rpms.size() + "\n");
|
||||
|
||||
outputDoubles(rpms, out, title);
|
||||
}
|
||||
|
||||
private static void outputDoubles(List<Double> values, BufferedWriter out, String title) throws IOException {
|
||||
out.write("static float " + title + "_table[] = {");
|
||||
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
if (i > 0)
|
||||
out.write(", ");
|
||||
out.write("/*" + i + "*/ " + values.get(i));
|
||||
|
||||
}
|
||||
out.write("};\n\n");
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package com.rusefi.logic;
|
||||
|
||||
/**
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
* 12/24/2015
|
||||
*/
|
||||
public class IgnitionMapBuilder {
|
||||
public enum ChamberStyle {
|
||||
OPEN_CHAMBER(33),
|
||||
CLOSED_CHAMBER(28),
|
||||
SWIRL_TUMBLE(22);
|
||||
|
||||
|
||||
private final int advance;
|
||||
|
||||
ChamberStyle(int advance) {
|
||||
this.advance = advance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static double getTopAdvanceForBore(ChamberStyle style, int octane, double compression, double bore) {
|
||||
int octaneCorrection;
|
||||
if ( octane <= 90) {
|
||||
octaneCorrection = -2;
|
||||
} else if (octane < 94) {
|
||||
octaneCorrection = -1;
|
||||
} else {
|
||||
octaneCorrection = 0;
|
||||
}
|
||||
|
||||
int compressionCorrection;
|
||||
if (compression <= 9) {
|
||||
compressionCorrection = 2;
|
||||
} else if (compression <= 10) {
|
||||
compressionCorrection = 1;
|
||||
} else if (compression <= 11) {
|
||||
compressionCorrection = 0;
|
||||
} else {
|
||||
// compression ratio above 11
|
||||
compressionCorrection = -2;
|
||||
}
|
||||
|
||||
double result = style.advance + octaneCorrection + compressionCorrection + getBoreCorrection(bore);
|
||||
return round10(result);
|
||||
}
|
||||
|
||||
public static double interpolate(double x1, double y1, double x2, double y2, double x) {
|
||||
double a = ((y1 - y2) / (x1 - x2));
|
||||
double b = y1 - a * x1;
|
||||
return a * x + b;
|
||||
}
|
||||
|
||||
public static double getAdvanceForRpm(int rpm, double advanceMax) {
|
||||
if (rpm >= 3000)
|
||||
return advanceMax;
|
||||
if (rpm < 600)
|
||||
return 10;
|
||||
return interpolate(600, 10, 3000, advanceMax, rpm);
|
||||
}
|
||||
|
||||
public static double getInitialAdvance(int rpm, double map, double advanceMax) {
|
||||
double advance = getAdvanceForRpm(rpm, advanceMax);
|
||||
|
||||
if (rpm > 3000)
|
||||
return round10(advance + 0.1 * (100 - map));
|
||||
|
||||
return round10(advance + 0.1 * (100 - map) * rpm / 3000);
|
||||
}
|
||||
|
||||
public static double round10(double result) {
|
||||
return ((int)(result * 10)) / 10.0;
|
||||
}
|
||||
|
||||
public static double getBoreCorrection(double bore) {
|
||||
return (bore - 4 * 25.4) / 25.4 * 6;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package com.rusefi.logic.test;
|
||||
|
||||
import com.rusefi.logic.IgnitionMapBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.rusefi.logic.IgnitionMapBuilder.*;
|
||||
import static com.rusefi.logic.IgnitionMapBuilder.ChamberStyle.*;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
* 12/24/2015
|
||||
*/
|
||||
public class IgnitionMapBuilderTest {
|
||||
private static final double EPS = 0.001;
|
||||
|
||||
@Test
|
||||
public void testIgnitionMapBuilder() {
|
||||
assertEquals(1.1, round10(1.1));
|
||||
assertEquals(1.1, round10(1.123));
|
||||
|
||||
assertEquals(0.0, getBoreCorrection(4 * 25.4));
|
||||
assertEquals(6.0, getBoreCorrection(5 * 25.4), EPS);
|
||||
|
||||
assertEquals(35.0, getTopAdvanceForBore(OPEN_CHAMBER, 98, 8, 101.6));
|
||||
assertEquals(33.0, getTopAdvanceForBore(OPEN_CHAMBER, 98, 11, 101.6));
|
||||
|
||||
assertEquals(22.0, getTopAdvanceForBore(SWIRL_TUMBLE, 89, 9, 101.6));
|
||||
assertEquals(32.2, getTopAdvanceForBore(SWIRL_TUMBLE, 89, 9, 145));
|
||||
|
||||
assertEquals(10.0, interpolate(0, 10, 10, 20, 0));
|
||||
assertEquals(20.0, interpolate(0, 10, 10, 20, 10));
|
||||
|
||||
assertEquals(10.0, getAdvanceForRpm(0, 36));
|
||||
assertEquals(10.0, getAdvanceForRpm(600, 36));
|
||||
assertEquals(36.0, getAdvanceForRpm(6500, 36));
|
||||
|
||||
assertEquals(16.5, getAdvanceForRpm(1200, 36));
|
||||
assertEquals(29.5, getAdvanceForRpm(2400, 36));
|
||||
|
||||
assertEquals(36.0, getInitialAdvance(6000, 100, 36));
|
||||
assertEquals(10.0, getInitialAdvance(600, 100, 36));
|
||||
|
||||
assertEquals(44.0, getInitialAdvance(6000, 20, 36));
|
||||
|
||||
assertEquals(34.3, getInitialAdvance(2400, 40, 36));
|
||||
assertEquals(42.0, getInitialAdvance(4400, 40, 36));
|
||||
assertEquals(11.6, getInitialAdvance(600, 20, 36));
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
import com.rusefi.FileLog;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 7/18/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class AverageData {
|
||||
public static XYData average(XYData data, int divider) {
|
||||
|
||||
double minX = data.getMinXValue();
|
||||
double xWidth = data.getMaxXValue() - minX;
|
||||
|
||||
FileLog.MAIN.logLine("From x" + minX + " w=" + xWidth);
|
||||
|
||||
XYData result = new XYData();
|
||||
|
||||
for (int i = 0; i < divider; i++) {
|
||||
double fromX_ = minX + (xWidth * i) / divider;
|
||||
double toX_ = minX + (xWidth * (i + 1)) / divider;
|
||||
|
||||
FileLog.MAIN.logLine("from " + fromX_ + " to " + toX_);
|
||||
|
||||
// double fromX = data.findXfromSet(fromX_);
|
||||
// double toX = data.findXfromSet(toX_);
|
||||
// System.out.println("from internal " + fromX + " to internal " + toX);
|
||||
|
||||
average(data, result, fromX_, toX_, divider);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void average(XYData data, XYData result, double fromX, double toX, int divider) {
|
||||
double minY = data.getMinYValue();
|
||||
double yWidth = data.getMaxYValue() - minY;
|
||||
|
||||
for (int i = 0; i < divider; i++) {
|
||||
double fromY_ = minY + (yWidth * i) / divider;
|
||||
double toY_ = minY + (yWidth * (i + 1)) / divider;
|
||||
|
||||
Set<Double> xRange = data.getXSet().tailSet(fromX).headSet(toX);
|
||||
|
||||
int counter = 0;
|
||||
double acc = 0;
|
||||
for (Double x : xRange) {
|
||||
YAxisData yData = data.getYAxis(x);
|
||||
|
||||
Set<Double> yRange = yData.getYs().tailSet(fromY_).headSet(toY_);
|
||||
|
||||
for (double y : yRange) {
|
||||
counter++;
|
||||
acc += yData.getValue(y);
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == 0)
|
||||
result.addPoint(new Point3D(fromX, fromY_, Float.NaN));
|
||||
else
|
||||
result.addPoint(new Point3D(fromX, fromY_, (float) (acc / counter)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
import com.rusefi.FileLog;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Date: 3/24/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*
|
||||
* @see com.rusefi.file.TableGenerator
|
||||
*/
|
||||
public class XYData {
|
||||
@NotNull
|
||||
private final TreeMap<Double, YAxisData> yDatas = new TreeMap<Double, YAxisData>();
|
||||
private double maxXValue;
|
||||
private double minXValue;
|
||||
|
||||
private double maxYValue;
|
||||
private double minYValue;
|
||||
|
||||
String date = FileLog.getDate();
|
||||
|
||||
public XYData() {
|
||||
clear();
|
||||
}
|
||||
|
||||
public float getValue(double x, double y) {
|
||||
YAxisData yAxis = findYAxis(x);
|
||||
if (yAxis == null)
|
||||
return Float.NaN; // empty map?
|
||||
return yAxis.findZ(y);
|
||||
}
|
||||
|
||||
public double getMaxXValue() {
|
||||
return maxXValue;
|
||||
}
|
||||
|
||||
public double getMinXValue() {
|
||||
return minXValue;
|
||||
}
|
||||
|
||||
public double getMaxYValue() {
|
||||
return maxYValue;
|
||||
}
|
||||
|
||||
public double getMinYValue() {
|
||||
return minYValue;
|
||||
}
|
||||
|
||||
public void addPoint(int rpm, double key, float value) {
|
||||
addPoint(new Point3D(rpm, key, value));
|
||||
}
|
||||
|
||||
public void addPoint(Point3D xyz) {
|
||||
YAxisData yAxis = getYdata(xyz);
|
||||
yAxis.addValue(xyz.getY(), xyz.getZ());
|
||||
}
|
||||
|
||||
public void setPoint(Point3D xyz) {
|
||||
YAxisData yAxis = getYdata(xyz);
|
||||
yAxis.setValue(xyz.getY(), xyz.getZ());
|
||||
}
|
||||
|
||||
private YAxisData getYdata(Point3D xyz) {
|
||||
minYValue = Math.min(minYValue, xyz.getY());
|
||||
maxYValue = Math.max(maxYValue, xyz.getY());
|
||||
return getYAxis(xyz.getX());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NavigableSet<Double> getXSet() {
|
||||
return yDatas.navigableKeySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public YAxisData getYAxis(double x) {
|
||||
YAxisData result = yDatas.get(x);
|
||||
if (result == null) {
|
||||
result = new YAxisData(x);
|
||||
maxXValue = Math.max(maxXValue, x);
|
||||
minXValue = Math.min(minXValue, x);
|
||||
yDatas.put(x, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public YAxisData findYAxis(double x) {
|
||||
double xfromSet = findXfromSet(x);
|
||||
if (Double.isNaN(xfromSet))
|
||||
return null;
|
||||
return yDatas.get(xfromSet);
|
||||
}
|
||||
|
||||
public double findXfromSet(double x) {
|
||||
Map.Entry<Double, YAxisData> floorEntry = yDatas.floorEntry(x);
|
||||
if (floorEntry != null)
|
||||
return floorEntry.getKey();
|
||||
Map.Entry<Double, YAxisData> ceilingEntry = yDatas.ceilingEntry(x);
|
||||
if (ceilingEntry == null)
|
||||
return Double.NaN;
|
||||
return ceilingEntry.getKey();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
maxXValue = Double.MIN_VALUE;
|
||||
minXValue = Double.MAX_VALUE;
|
||||
maxYValue = Double.MIN_VALUE;
|
||||
minYValue = Double.MAX_VALUE;
|
||||
yDatas.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "XYData{" +
|
||||
"yDatas.size()=" + yDatas.size() +
|
||||
'}';
|
||||
}
|
||||
|
||||
public void saveToFile(String filename) {
|
||||
try {
|
||||
String name = date + filename;
|
||||
FileLog.MAIN.logLine("Writing data to " + name);
|
||||
Writer w = new FileWriter(name);
|
||||
for (YAxisData yAxisData : yDatas.values())
|
||||
yAxisData.write(w);
|
||||
|
||||
w.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(Range rpmRange, Range keyRange, int count, float value) {
|
||||
clear();
|
||||
for (int i = 0; i < count; i++)
|
||||
for (int j = 0; j < count; j++) {
|
||||
|
||||
float rpm = rpmRange.getMin() + (rpmRange.getWidth() * i / count);
|
||||
float key = keyRange.getMin() + (keyRange.getWidth() * j / count);
|
||||
|
||||
|
||||
addPoint(new Point3D(rpm, key, value));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
import com.rusefi.FileLog;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* 6/30/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class XYDataReader {
|
||||
public static XYData readFile(String fileName) {
|
||||
if (!new File(fileName).exists())
|
||||
throw new IllegalArgumentException("No file: " + fileName);
|
||||
try {
|
||||
return doReadFile(fileName);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static XYData doReadFile(String fileName) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(fileName));
|
||||
String line;
|
||||
XYData data = new XYData();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
//process each line in some way
|
||||
Point3D xyz = Point3D.parseLine(line);
|
||||
data.addPoint(xyz);
|
||||
}
|
||||
FileLog.MAIN.logLine("x range: " + data.getMinXValue() + " to " + data.getMaxXValue());
|
||||
FileLog.MAIN.logLine("y range: " + data.getMinYValue() + " to " + data.getMaxYValue());
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
package com.rusefi.models;
|
||||
|
||||
import com.rusefi.FileLog;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Y>Z mapping for the same X
|
||||
* <p/>
|
||||
* Date: 3/24/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class YAxisData {
|
||||
private final TreeMap<Double, ValuesHolder> values = new TreeMap<Double, ValuesHolder>();
|
||||
private double maxYValue = Double.MIN_VALUE;
|
||||
private double minYValue = Double.MAX_VALUE;
|
||||
private final double x;
|
||||
|
||||
public YAxisData(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public NavigableSet<Double> getYs() {
|
||||
return values.navigableKeySet();
|
||||
}
|
||||
|
||||
public float findZ(double y) {
|
||||
Map.Entry<Double, ValuesHolder> entry = values.floorEntry(y);
|
||||
if (entry != null)
|
||||
return entry.getValue().get();
|
||||
return values.ceilingEntry(y).getValue().get();
|
||||
}
|
||||
|
||||
public void setValue(double y, float value) {
|
||||
ValuesHolder holder = getHolder(y);
|
||||
holder.set(value);
|
||||
}
|
||||
|
||||
public void addValue(double y, float value) {
|
||||
ValuesHolder holder = getHolder(y);
|
||||
|
||||
holder.add(value);
|
||||
|
||||
float newAvg = holder.get();
|
||||
if (newAvg != value && !Float.isNaN(newAvg)) {
|
||||
FileLog.MAIN.logLine("new " + value + " avg " + newAvg + " for x=" + x + "/y=" + y);
|
||||
}
|
||||
}
|
||||
|
||||
private ValuesHolder getHolder(double y) {
|
||||
minYValue = Math.min(minYValue, y);
|
||||
maxYValue = Math.max(maxYValue, y);
|
||||
|
||||
ValuesHolder holder = values.get(y);
|
||||
if (holder == null)
|
||||
values.put(y, holder = new ValuesHolder());
|
||||
return holder;
|
||||
}
|
||||
|
||||
public double getValue(double y) {
|
||||
return values.get(y).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "YAxisData{" +
|
||||
"size=" + values.size() +
|
||||
", maxYValue=" + maxYValue +
|
||||
", minYValue=" + minYValue +
|
||||
", x=" + x +
|
||||
'}';
|
||||
}
|
||||
|
||||
public void write(Writer w) throws IOException {
|
||||
for (Map.Entry<Double, ValuesHolder> e : values.entrySet())
|
||||
w.write("rpm," + x + ",key," + e.getKey() + ",value," + e.getValue().get() + "\r\n");
|
||||
}
|
||||
|
||||
private static class ValuesHolder {
|
||||
|
||||
private float total;
|
||||
private int count;
|
||||
|
||||
private ValuesHolder() {
|
||||
}
|
||||
|
||||
public float get() {
|
||||
return total / count;
|
||||
}
|
||||
|
||||
public void add(float value) {
|
||||
total += value;
|
||||
count++;
|
||||
}
|
||||
|
||||
public void set(float value) {
|
||||
total = value;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package com.rusefi.ui;
|
||||
|
||||
//import com.rusefi.EcuStimulator;
|
||||
import com.rusefi.core.MessagesCentral;
|
||||
import com.rusefi.models.Point3D;
|
||||
import com.rusefi.models.Range;
|
||||
import com.rusefi.models.XYData;
|
||||
//import net.ericaro.surfaceplotter.DefaultSurfaceModel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* 7/22/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
/*
|
||||
public class Live3DReport {
|
||||
public static final Range KEY_RANGE = new Range(1.5f, 4.0f);
|
||||
private final XYData primary = new XYData();
|
||||
private final XYData secondary = null;//new XYData();
|
||||
private final JPanel control;
|
||||
|
||||
private static final String KEY = "map_adjusted: ";
|
||||
|
||||
public Live3DReport() {
|
||||
final DefaultSurfaceModel model = ChartHelper.createDefaultSurfaceModel(primary, EcuStimulator.RPM_RANGE, KEY_RANGE, secondary);
|
||||
|
||||
// primary.fill(EcuStimulator.RPM_RANGE, KEY_RANGE, 16, 1);
|
||||
|
||||
control = ChartHelper.create3DControl(primary, model, "Live Data");
|
||||
|
||||
// addPoint("1000 3 0.9", model);
|
||||
// addPoint("1000 320 90", model);
|
||||
// addPoint("1000 340 90", model);
|
||||
|
||||
MessagesCentral.getInstance().addListener(new MessagesCentral.MessageListener() {
|
||||
@Override
|
||||
public void onMessage(Class clazz, String message) {
|
||||
if (!message.startsWith(KEY))
|
||||
return;
|
||||
message = message.substring(KEY.length());
|
||||
addPoint(message, model);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addPoint(String message, DefaultSurfaceModel model) {
|
||||
String[] v = message.split(" ");
|
||||
if (v.length != 3)
|
||||
return;
|
||||
|
||||
int rpm = Integer.parseInt(v[0]);
|
||||
float key = Integer.parseInt(v[1]) / 100.0f;
|
||||
float value = Integer.parseInt(v[2]) / 100.0f;
|
||||
|
||||
primary.setPoint(new Point3D(rpm, key, value));
|
||||
primary.saveToFile("_mult.csv");
|
||||
model.plot().execute();
|
||||
}
|
||||
|
||||
public Component getControl() {
|
||||
return control;
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -1,27 +0,0 @@
|
|||
package com.rusefi.ui;
|
||||
|
||||
import com.rusefi.file.BaseMap;
|
||||
import com.rusefi.models.XYData;
|
||||
import com.rusefi.core.ui.FrameHelper;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* 7/18/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
/*
|
||||
public class ShowMap {
|
||||
public static void main(String[] args) {
|
||||
// XYData data = BaseMap.loadData("a.csv", "maf", "af");
|
||||
// XYData data2 = BaseMap.loadData("a.csv", "maf", "table_fuel");
|
||||
|
||||
XYData data = BaseMap.loadData("200.csv", "maf", "dwell");
|
||||
XYData data2 = null;
|
||||
|
||||
JPanel jsp = ChartHelper.create3DControl(data, ChartHelper.createDefaultSurfaceModel(data, data2), "MAF<>Fuel Map");
|
||||
|
||||
new FrameHelper().showFrame(jsp);
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -1,159 +0,0 @@
|
|||
package com.rusefi.ui;
|
||||
|
||||
import com.rusefi.AverageAnglePanel;
|
||||
import com.rusefi.core.Sensor;
|
||||
import com.rusefi.core.SensorCentral;
|
||||
import com.rusefi.OutputChannel;
|
||||
import com.rusefi.io.CommandQueue;
|
||||
import com.rusefi.io.InvocationConfirmationListener;
|
||||
import com.rusefi.trigger.TriggerShapeHolder;
|
||||
import com.rusefi.ui.util.UiUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 1/17/2015
|
||||
*/
|
||||
public class Wizard {
|
||||
private final JPanel panel = new JPanel(new BorderLayout());
|
||||
private final JPanel content = new JPanel();
|
||||
private final JButton button = new JButton("Trigger Wizard");
|
||||
|
||||
interface WizardStep {
|
||||
Component getContent();
|
||||
}
|
||||
|
||||
abstract static class WizardStepImpl implements WizardStep {
|
||||
protected WizardStep nextStep;
|
||||
|
||||
public WizardStepImpl() {
|
||||
}
|
||||
|
||||
public WizardStepImpl setNext(WizardStepImpl nextStep) {
|
||||
this.nextStep = nextStep;
|
||||
return nextStep;
|
||||
}
|
||||
}
|
||||
|
||||
class SendCommand extends WizardStepImpl {
|
||||
private final String command;
|
||||
|
||||
SendCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getContent() {
|
||||
CommandQueue instance = null;
|
||||
instance.write(command, CommandQueue.DEFAULT_TIMEOUT, new InvocationConfirmationListener() {
|
||||
@Override
|
||||
public void onCommandConfirmation() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
applyStep(nextStep);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return new JLabel("Sending " + command);
|
||||
}
|
||||
}
|
||||
|
||||
private final WizardStepImpl TRIGGER_WIZARD_HELLO = new WizardStepImpl() {
|
||||
@Override
|
||||
public Component getContent() {
|
||||
JButton button = new JButton("Hello, let's test trigger. Click this to process");
|
||||
button.addActionListener(new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
applyStep(nextStep);
|
||||
}
|
||||
});
|
||||
return button;
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
TRIGGER_WIZARD_HELLO.setNext(new SendCommand("disable injection"))
|
||||
.setNext(new SendCommand("disable ignition"))
|
||||
.setNext(new SendCommand("chartsize " + (10 * TriggerShapeHolder.CURRENT.getTotalToothCount() * 2)))
|
||||
.setNext(new SendCommand("subscribe " + OutputChannel.WaveChartCurrentSize.getProtocolId()))
|
||||
.setNext(new SendCommand("subscribe " + OutputChannel.RunningTriggerError.getProtocolId()))
|
||||
.setNext(new SendCommand("subscribe " + OutputChannel.RunningOrderingTriggerError.getProtocolId()))
|
||||
.setNext(new SendCommand("set_analog_chart_freq " + 1))
|
||||
.setNext(new WaitForZeroRpm())
|
||||
;
|
||||
}
|
||||
|
||||
public Component createPane() {
|
||||
panel.add(button, BorderLayout.NORTH);
|
||||
|
||||
panel.add(content, BorderLayout.CENTER);
|
||||
|
||||
panel.add(new AverageAnglePanel(null).getPanel(), BorderLayout.SOUTH);
|
||||
|
||||
button.addActionListener(new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
button.setEnabled(false);
|
||||
|
||||
applyStep(Wizard.this.TRIGGER_WIZARD_HELLO);
|
||||
}
|
||||
});
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void applyStep(WizardStep step) {
|
||||
System.out.println(new Date() + " apply " + step);
|
||||
Component newContent = getContent(step);
|
||||
content.removeAll();
|
||||
content.add(newContent);
|
||||
UiUtils.trueLayout(content);
|
||||
}
|
||||
|
||||
private Component getContent(WizardStep step) {
|
||||
Component newContent;
|
||||
if (step == null) {
|
||||
newContent = new JLabel("Wizard is done!");
|
||||
button.setEnabled(true);
|
||||
} else {
|
||||
newContent = step.getContent();
|
||||
}
|
||||
return newContent;
|
||||
}
|
||||
|
||||
private class WaitForZeroRpm extends WizardStepImpl {
|
||||
private int counter;
|
||||
|
||||
@Override
|
||||
public Component getContent() {
|
||||
double rpm = SensorCentral.getInstance().getValue(Sensor.RPMValue);
|
||||
if (rpm == 0) {
|
||||
return Wizard.this.getContent(nextStep);
|
||||
}
|
||||
|
||||
scheduleRepaint(1000, this);
|
||||
|
||||
return new JLabel("Current RPM: " + rpm + ", please stop the engine. Waiting " + counter++);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleRepaint(int timeoutMs, final WizardStep step) {
|
||||
final AtomicReference<Timer> tHolder = new AtomicReference<>();
|
||||
Timer t = new Timer(timeoutMs, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tHolder.get().stop();
|
||||
applyStep(step);
|
||||
}
|
||||
});
|
||||
tHolder.set(t);
|
||||
t.start();
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package com.rusefi.models.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
public class SoftLimiterSandbox {
|
||||
private Random r = new Random();
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SoftLimiterSandbox().testSoftLimit();
|
||||
}
|
||||
|
||||
public void testSoftLimit() {
|
||||
double targetMissRatio = 0.3;
|
||||
|
||||
int windowSize = 50;
|
||||
State state = new State(windowSize);
|
||||
|
||||
System.out.println("Target miss ratio: " + targetMissRatio);
|
||||
System.out.println("Window length: " + windowSize);
|
||||
System.out.println("eventIndex,state,currentWindowDeepRatio");
|
||||
|
||||
for (int i = 0; i < 250 * windowSize; i++) {
|
||||
state.add(targetMissRatio);
|
||||
System.out.println(i + "," + state.getLatest() + "," + state.getCurrentRatio());
|
||||
}
|
||||
}
|
||||
|
||||
class State {
|
||||
private final int windowSize;
|
||||
|
||||
ArrayList<Boolean> states = new ArrayList<>();
|
||||
|
||||
|
||||
public State(int windowSize) {
|
||||
this.windowSize = windowSize;
|
||||
states.add(false);
|
||||
}
|
||||
|
||||
boolean getLatest() {
|
||||
return states.get(states.size() - 1);
|
||||
}
|
||||
|
||||
double getCurrentRatio() {
|
||||
int from = Math.max(0, states.size() - windowSize);
|
||||
int count = 0;
|
||||
for (int i = from; i < states.size(); i++) {
|
||||
if (states.get(i))
|
||||
count++;
|
||||
}
|
||||
return count * 1.0 / windowSize;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void add(double targetMissRatio) {
|
||||
if (!getLatest()) {
|
||||
// never skip two in a row
|
||||
states.add(true);
|
||||
} else {
|
||||
double currentRatio = getCurrentRatio();
|
||||
//double thisEventProbability =
|
||||
|
||||
/**
|
||||
* Due to "never miss two events in a row" requirement we want more or less double the target in comparison
|
||||
* if current ratio is above target we want to lower probability for next event to fire
|
||||
*/
|
||||
|
||||
boolean newState = r.nextDouble() > 2 * targetMissRatio;
|
||||
states.add(newState);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package com.rusefi.models.test;
|
||||
|
||||
import com.rusefi.models.XYData;
|
||||
|
||||
/**
|
||||
* 7/24/13
|
||||
* Andrey Belomutskiy, (c) 2013-2020
|
||||
*/
|
||||
public class XYDataSandbox {
|
||||
public static void main(String[] args) {
|
||||
XYData d = new XYData();
|
||||
|
||||
d.addPoint(600, 3, 11);
|
||||
d.addPoint(600, 3.1, 11);
|
||||
|
||||
d.addPoint(1600, 3.1, 11);
|
||||
|
||||
d.saveToFile("_mult.dat");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue