progress
This commit is contained in:
parent
38cb52b77a
commit
45b9355640
|
@ -63,4 +63,13 @@ public class AfrDataPoint {
|
|||
public double getEngineLoad() {
|
||||
return engineLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AfrDataPoint{" +
|
||||
"afr=" + afr +
|
||||
", rpm=" + rpm +
|
||||
", engineLoad=" + engineLoad +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,5 +8,5 @@ import java.util.Collection;
|
|||
*/
|
||||
public interface FuelAutoLogic {
|
||||
// void MainWindow::calckGBC(double STEP)
|
||||
Result process(boolean smooth, Collection<AfrDataPoint> dataECU, double STEP, double targetAFR, float[][] kgbcINIT);
|
||||
Result process(boolean smooth, Collection<AfrDataPoint> dataECU, double STEP, double targetAFR, double[][] kgbcINIT);
|
||||
}
|
||||
|
|
|
@ -17,21 +17,18 @@ public enum FuelAutoTune implements FuelAutoLogic {
|
|||
// Fields.FUEL_RPM_COUNT
|
||||
// Fields.FUEL_LOAD_COUNT
|
||||
public static final int SIZE = 16;
|
||||
public static final double _14_7 = 14.7;
|
||||
|
||||
private static boolean isLogEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// private static final int TEMP_CORR = 39;
|
||||
|
||||
|
||||
// void MainWindow::calckGBC(double STEP)
|
||||
@Override
|
||||
public Result process(boolean smooth, Collection<AfrDataPoint> dataECU, double STEP, double targetAFR, float[][] kgbcINIT) {
|
||||
double kgbcSQ[][] = new double[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
double kgbcSQsum = 0;
|
||||
double kgbcSQsumLast;
|
||||
double minSQtotal = 1e+15;
|
||||
public Result process(boolean smooth, Collection<AfrDataPoint> dataECU, double STEP, double targetAFR, double[][] kgbcINIT) {
|
||||
double cellDeviation[][] = new double[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
double totalDeviation = 0;
|
||||
double minSQtotal = Double.MAX_VALUE;
|
||||
double kgbcSQsumLastTotal = 1e+16;
|
||||
double ksq = 1000; //???? ??????????????????? ??????????
|
||||
double ke = 100; //???? ??????????
|
||||
|
@ -43,7 +40,7 @@ public enum FuelAutoTune implements FuelAutoLogic {
|
|||
bkGBC[data.PRESS_RT_32()][data.RPM_RT_32()]++;
|
||||
}
|
||||
|
||||
float result[][] = MathUtil.deepCopy(kgbcINIT);
|
||||
double result[][] = MathUtil.deepCopy(kgbcINIT);
|
||||
|
||||
double ktgbcRES[][] = new double[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
double ktgbcINIT[][] = new double[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
|
@ -54,88 +51,97 @@ public enum FuelAutoTune implements FuelAutoLogic {
|
|||
int COUNT_THRESHOLD = 20; // minimal number of measurements in cell to be considered
|
||||
|
||||
int minK = 0; // todo: what is this?
|
||||
while (true) {
|
||||
while (minK <= 4) {
|
||||
for (int loadIndex = 0; loadIndex < FUEL_LOAD_COUNT; loadIndex++) {
|
||||
for (int rpmIndex = 0; rpmIndex < FUEL_RPM_COUNT; rpmIndex++) {
|
||||
if (bkGBC[loadIndex][rpmIndex] < COUNT_THRESHOLD)
|
||||
continue;
|
||||
|
||||
//log("Processing " + r + "/c" + c);
|
||||
|
||||
double minSQ = 1e+16;
|
||||
kgbcSQsum = 1e+16;
|
||||
|
||||
double step = STEP;
|
||||
double mink = 0;
|
||||
while (true) {
|
||||
////////////////////////////////////
|
||||
//????????? ?????????? ? ????????
|
||||
MathUtil.setArray2D(kgbcSQ, 0);
|
||||
|
||||
kgbcSQsumLast = kgbcSQsum;
|
||||
|
||||
countDeviation(dataECU, kgbcSQ, result, kgbcINIT, targetAFR);
|
||||
|
||||
kgbcSQsum = MathUtil.sumArray(kgbcSQ);
|
||||
|
||||
if (smooth) {
|
||||
kgbcSQsum = smooth(kgbcSQsum, ksq, ke, kg, result);
|
||||
}
|
||||
////////////////////////////////////
|
||||
if (kgbcSQsum >= kgbcSQsumLast)
|
||||
step = -step;
|
||||
//???? ?????? ?? ??????? ????? ???, ?? ? ?? ?????????? ??
|
||||
/*if(bkGBC[r][c]) */
|
||||
|
||||
// log("Adjusting " + step);
|
||||
result[loadIndex][rpmIndex] += step;
|
||||
if (kgbcSQsum < minSQ)
|
||||
minSQ = kgbcSQsum;
|
||||
|
||||
if (Math.abs(minSQ - kgbcSQsumLast) < 1e-10)
|
||||
mink++;
|
||||
if (mink > 4) {
|
||||
// updateTablekGBC();
|
||||
// ui -> statusBar -> showMessage(QString::number (kgbcSQsum), 500);
|
||||
log("break " + rpmIndex + "/" + loadIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
totalDeviation = getTotalDeviationAfterCellOptimization(smooth, dataECU, STEP, targetAFR, kgbcINIT, cellDeviation, ksq, ke, kg, result, loadIndex, rpmIndex);
|
||||
}
|
||||
}
|
||||
if (kgbcSQsum < minSQtotal)
|
||||
minSQtotal = kgbcSQsum;
|
||||
|
||||
|
||||
if (totalDeviation < minSQtotal)
|
||||
minSQtotal = totalDeviation;
|
||||
if (Math.abs(minSQtotal - kgbcSQsumLastTotal) < 1e-10)
|
||||
minK++;
|
||||
if (minK > 4) {
|
||||
//updateTablekGBC();
|
||||
//ui->statusBar->showMessage(QString::number(kgbcSQsum), 500);
|
||||
log("return " + minK);
|
||||
return new Result(result);
|
||||
}
|
||||
kgbcSQsumLastTotal = kgbcSQsum;
|
||||
kgbcSQsumLastTotal = totalDeviation;
|
||||
//ui->statusBar->showMessage(QString::number(gbcSQsum));
|
||||
//updateTableGBC();
|
||||
|
||||
}
|
||||
|
||||
log("return " + minK);
|
||||
return new Result(result);
|
||||
}
|
||||
|
||||
private static void countDeviation(Collection<AfrDataPoint> dataECU, double[][] kgbcSQ, float[][] kgbcRES, float[][] kgbcINIT, double targetAFR) {
|
||||
/**
|
||||
* Optimize one table cell
|
||||
* @return total deviation of the whole map
|
||||
*/
|
||||
private static double getTotalDeviationAfterCellOptimization(
|
||||
boolean smooth, Collection<AfrDataPoint> dataECU, double step,
|
||||
double targetAFR, double[][] kgbcINIT, double[][] cellDeviation,
|
||||
double ksq, double ke, double kg, double[][] result, int loadIndex, int rpmIndex) {
|
||||
double totalDeviation = Double.MAX_VALUE;
|
||||
double minTotalDeviation = Double.MAX_VALUE;
|
||||
double prevTotalDeviation;
|
||||
|
||||
double currentStep = step;
|
||||
int goodValueCounter = 0;
|
||||
while (goodValueCounter <= 4) {
|
||||
prevTotalDeviation = totalDeviation;
|
||||
|
||||
// todo: since we are only adjusting one cell there is not point to recalculate all deviations
|
||||
// todo: potential CPU usage optimization here
|
||||
countDeviation(dataECU, cellDeviation, result, kgbcINIT, targetAFR);
|
||||
|
||||
totalDeviation = MathUtil.sumArray(cellDeviation);
|
||||
|
||||
if (smooth) {
|
||||
totalDeviation = smooth(totalDeviation, ksq, ke, kg, result);
|
||||
}
|
||||
////////////////////////////////////
|
||||
if (totalDeviation >= prevTotalDeviation)
|
||||
currentStep = -currentStep;
|
||||
//???? ?????? ?? ??????? ????? ???, ?? ? ?? ?????????? ??
|
||||
/*if(bkGBC[r][c]) */
|
||||
|
||||
// log("Adjusting " + currentStep);
|
||||
result[loadIndex][rpmIndex] += currentStep;
|
||||
|
||||
minTotalDeviation = Math.min(minTotalDeviation, totalDeviation);
|
||||
|
||||
if (Math.abs(minTotalDeviation - prevTotalDeviation) < 1e-10)
|
||||
goodValueCounter++;
|
||||
}
|
||||
return totalDeviation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculated all per-cell deviations of all data points over whole table
|
||||
*/
|
||||
private static void countDeviation(Collection<AfrDataPoint> dataECU, double[][] cellDeviation, double[][] result, double[][] kgbcINIT, double targetAFR) {
|
||||
MathUtil.setArray2D(cellDeviation, 0);
|
||||
double normalizedTargetAfr = targetAFR / _14_7;
|
||||
|
||||
for (AfrDataPoint dataPoint : dataECU) {
|
||||
double ALF = targetAFR / 14.7;
|
||||
double tmp = (dataPoint.getAfr() / 14.7 - ALF *
|
||||
(kgbcRES[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()]) /
|
||||
double normalizedAfr = dataPoint.getAfr() / _14_7;
|
||||
|
||||
double tmp = (normalizedAfr - normalizedTargetAfr *
|
||||
(result[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()]) /
|
||||
(kgbcINIT[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()]));
|
||||
|
||||
// if (isLogEnabled())
|
||||
// log("r=" + r + "/c=" + c + ": tmp=" + tmp);
|
||||
|
||||
// kgbcSQ[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()] += tmp * tmp; todo: what is this deviation called?
|
||||
kgbcSQ[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()] += Math.abs(tmp); // todo: what is this deviation called?
|
||||
// cellDeviation[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()] += tmp * tmp; todo: what is this deviation called?
|
||||
cellDeviation[dataPoint.PRESS_RT_32()][dataPoint.RPM_RT_32()] += Math.abs(tmp); // todo: what is this deviation called?
|
||||
}
|
||||
}
|
||||
|
||||
private static double smooth(double kgbcSQsum, double ksq, double ke, double kg, float[][] kgbcRES) {
|
||||
private static double smooth(double kgbcSQsum, double ksq, double ke, double kg, double[][] kgbcRES) {
|
||||
double e = 0;
|
||||
kgbcSQsum = ksq * kgbcSQsum;
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ public enum FuelAutoTune2 implements FuelAutoLogic {
|
|||
|
||||
|
||||
@Override
|
||||
public Result process(boolean smooth, Collection<AfrDataPoint> dataECU, double GRAD, double targetAFR, float[][] VEcur) {
|
||||
float result[][] = new float[SIZE][SIZE];
|
||||
public Result process(boolean smooth, Collection<AfrDataPoint> dataECU, double GRAD, double targetAFR, double[][] VEcur) {
|
||||
double result[][] = new double[SIZE][SIZE];
|
||||
|
||||
// proverka na statichnost' rezhimnoy tochki
|
||||
boolean fl_static = true;
|
||||
|
|
|
@ -10,10 +10,10 @@ public class MathUtil {
|
|||
private MathUtil() {
|
||||
}
|
||||
|
||||
static float[][] deepCopy(float[][] input) {
|
||||
static double[][] deepCopy(double[][] input) {
|
||||
if (input == null)
|
||||
return null;
|
||||
float[][] result = new float[input.length][];
|
||||
double[][] result = new double[input.length][];
|
||||
for (int r = 0; r < input.length; r++) {
|
||||
result[r] = input[r].clone();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class MathUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
static void setArray2D(double[][] array, double value) {
|
||||
public static void setArray2D(double[][] array, double value) {
|
||||
for (double[] a : array)
|
||||
Arrays.setAll(a, i -> value);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ package com.rusefi.autotune;
|
|||
* 2/23/2016.
|
||||
*/
|
||||
public class Result {
|
||||
private final float[][] kgbcRES;
|
||||
private final double[][] kgbcRES;
|
||||
|
||||
public Result(float[][] kgbcRES) {
|
||||
public Result(double[][] kgbcRES) {
|
||||
this.kgbcRES = kgbcRES;
|
||||
}
|
||||
|
||||
public float[][] getKgbcRES() {
|
||||
public double[][] getKgbcRES() {
|
||||
return kgbcRES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,62 @@
|
|||
package com.rusefi.autotune.test;
|
||||
|
||||
import com.rusefi.autotune.FuelAutoTune;
|
||||
import com.rusefi.autotune.Result;
|
||||
import com.rusefi.autotune.AfrDataPoint;
|
||||
import com.rusefi.autotune.*;
|
||||
import com.rusefi.config.Fields;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* 1/5/2016
|
||||
* (c) Andrey Belomutskiy 2013-2017
|
||||
*/
|
||||
public class FuelAutoTuneTest {
|
||||
private static final double EPS = 0.00001;
|
||||
|
||||
@Test
|
||||
public void testAlreadyTuned() {
|
||||
double value = 0.7;
|
||||
double[][] veTable = createVeTable(value);
|
||||
List<AfrDataPoint> dataPoints = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
dataPoints.add(AfrDataPoint.valueOf(FuelAutoTune._14_7, 1500 + i, 50));
|
||||
Result r = FuelAutoTune.INSTANCE.process(false, dataPoints, 0.1, FuelAutoTune._14_7, veTable);
|
||||
|
||||
assertEquals(0, countNotEqual(r.getKgbcRES(), value));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptimizeOneCell() {
|
||||
|
||||
double value = 0.7;
|
||||
double[][] veTable = createVeTable(value);
|
||||
List<AfrDataPoint> allSamePoints = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
allSamePoints.add(AfrDataPoint.valueOf(10, 1500, 50));
|
||||
|
||||
Result r = FuelAutoTune.INSTANCE.process(false, allSamePoints, 0.1, FuelAutoTune._14_7, veTable);
|
||||
|
||||
printNotDefault(r.getKgbcRES(), value);
|
||||
assertEquals(0.5, r.getKgbcRES()[6][3], EPS);
|
||||
assertEquals(1, countNotEqual(r.getKgbcRES(), value));
|
||||
}
|
||||
|
||||
|
||||
private int countNotEqual(double[][] array2D, double value) {
|
||||
int result = 0;
|
||||
for (double array[] : array2D) {
|
||||
for (double v : array)
|
||||
if (v != value)
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAutoTune() {
|
||||
|
@ -54,26 +97,22 @@ public class FuelAutoTuneTest {
|
|||
/**
|
||||
* this method prints all values which do not equal default value
|
||||
*/
|
||||
static void printNotDefault(float[][] array, double defaultValue) {
|
||||
static void printNotDefault(double[][] array, double defaultValue) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
printNotDefault(array[i], i, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printNotDefault(float[] array, int index, double defaultValue) {
|
||||
private static void printNotDefault(double[] array, int index, double defaultValue) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (array[i] != defaultValue)
|
||||
System.out.println("Found value: x=" + index + " y=" + i + ": " + array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static float[][] createVeTable(int value) {
|
||||
float veMap[][] = new float[Fields.FUEL_LOAD_COUNT][Fields.FUEL_RPM_COUNT];
|
||||
for (int engineLoadIndex = 0; engineLoadIndex < Fields.FUEL_LOAD_COUNT; engineLoadIndex++) {
|
||||
for (int rpmIndex = 0; rpmIndex < Fields.FUEL_RPM_COUNT; rpmIndex++) {
|
||||
veMap[engineLoadIndex][rpmIndex] = value;
|
||||
}
|
||||
}
|
||||
static double[][] createVeTable(double value) {
|
||||
double veMap[][] = new double[Fields.FUEL_LOAD_COUNT][Fields.FUEL_RPM_COUNT];
|
||||
MathUtil.setArray2D(veMap, value);
|
||||
return veMap;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue