This commit is contained in:
rusefi 2018-09-02 22:15:07 -04:00
parent 38cb52b77a
commit 45b9355640
7 changed files with 142 additions and 88 deletions

View File

@ -63,4 +63,13 @@ public class AfrDataPoint {
public double getEngineLoad() {
return engineLoad;
}
@Override
public String toString() {
return "AfrDataPoint{" +
"afr=" + afr +
", rpm=" + rpm +
", engineLoad=" + engineLoad +
'}';
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}