Skip to content

Commit

Permalink
Idle PID Coasting & Amplification Improvements (#589)
Browse files Browse the repository at this point in the history
* PID Error Amplification Coef

* Add settings: useIacTableForCoasting,pidExtraForLowRpm,iacCoasting

* Modify interface for the new settings

* Run gen_config.bat and generate configs

* idlePositionSensitivityThreshold

* Remove cltCorrection from autoIdle() & more verbose debug

* Impl. idlePidRpmDeadZone and pidExtraForLowRpm; reset PID when deactivated

* Impl. useIacTableForCoasting+iacCoasting and idlePidRpmUpperLimit
  • Loading branch information
andreika-git authored and rusefi committed Mar 30, 2018
1 parent b55dda9 commit 99ea4ee
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 31 deletions.
@@ -1,4 +1,4 @@
// this section was generated automatically by ConfigDefinition.jar based on rusefi_config.txt Thu Mar 22 08:12:47 EDT 2018
// this section was generated automatically by ConfigDefinition.jar based on rusefi_config.txt Wed Mar 28 16:53:17 EEST 2018
// begin
#ifndef ENGINE_CONFIGURATION_GENERATED_H_
#define ENGINE_CONFIGURATION_GENERATED_H_
Expand Down Expand Up @@ -648,7 +648,7 @@ typedef struct {
bool coastingFuelCutEnabled : 1;
/**
offset 376 bit 22 */
bool unused_board_984_22 : 1;
bool useIacTableForCoasting : 1;
/**
offset 376 bit 23 */
bool unused_board_984_23 : 1;
Expand Down Expand Up @@ -2117,9 +2117,28 @@ typedef struct {
*/
int16_t coastingFuelCutClt;
/**
* Increases PID reaction for RPM<target by adding extra percent to PID-error
* offset 3384
*/
int unusedEnd[774];
int16_t pidExtraForLowRpm;
/**
* offset 3386
*/
int16_t unusedInt16;
/**
* CLT-based idle position for coasting (used in Auto-PID Idle mode)
* offset 3388
*/
float iacCoastingBins[CLT_CURVE_SIZE];
/**
* CLT-based idle position for coasting (used in Auto-PID Idle mode)
* offset 3452
*/
float iacCoasting[CLT_CURVE_SIZE];
/**
* offset 3516
*/
int unusedEnd[741];
/** total size 6480*/
} engine_configuration_s;

Expand Down Expand Up @@ -2203,12 +2222,12 @@ typedef struct {
*/
float crankingCycleBins[CRANKING_CURVE_SIZE];
/**
* CLT-based idle position multiplier for simple manual idle controller, or target RPM multiplier for PID-based idle
* CLT-based idle position multiplier for simple manual idle controller
* offset 10656
*/
float cltIdleCorrBins[CLT_CURVE_SIZE];
/**
* CLT-based idle position multiplier for simple manual idle controller, or target RPM multiplier for PID-based idle
* CLT-based idle position multiplier for simple manual idle controller
* offset 10720
*/
float cltIdleCorr[CLT_CURVE_SIZE];
Expand Down Expand Up @@ -2365,4 +2384,4 @@ typedef struct {

#endif
// end
// this section was generated automatically by ConfigDefinition.jar based on rusefi_config.txt Thu Mar 22 08:12:47 EDT 2018
// this section was generated automatically by ConfigDefinition.jar based on rusefi_config.txt Wed Mar 28 16:53:17 EEST 2018
16 changes: 12 additions & 4 deletions firmware/controllers/algo/rusefi_generated.h
Expand Up @@ -588,8 +588,8 @@
#define isFasterEngineSpinUpEnabled_offset_hex 3d8
#define coastingFuelCutEnabled_offset 984
#define coastingFuelCutEnabled_offset_hex 3d8
#define unused_board_984_22_offset 984
#define unused_board_984_22_offset_hex 3d8
#define useIacTableForCoasting_offset 984
#define useIacTableForCoasting_offset_hex 3d8
#define unused_board_984_23_offset 984
#define unused_board_984_23_offset_hex 3d8
#define unused_board_984_24_offset 984
Expand Down Expand Up @@ -1560,8 +1560,16 @@
#define coastingFuelCutTps_offset_hex d34
#define coastingFuelCutClt_offset 3382
#define coastingFuelCutClt_offset_hex d36
#define unusedEnd_offset 3384
#define unusedEnd_offset_hex d38
#define pidExtraForLowRpm_offset 3384
#define pidExtraForLowRpm_offset_hex d38
#define unusedInt16_offset 3386
#define unusedInt16_offset_hex d3a
#define iacCoastingBins_offset 3388
#define iacCoastingBins_offset_hex d3c
#define iacCoasting_offset 3452
#define iacCoasting_offset_hex d7c
#define unusedEnd_offset 3516
#define unusedEnd_offset_hex dbc
#define cltCrankingCorrBins_offset 6480
#define cltCrankingCorrBins_offset_hex 1950
#define cltCrankingCorr_offset 6512
Expand Down
59 changes: 55 additions & 4 deletions firmware/controllers/idle_thread.cpp
Expand Up @@ -44,6 +44,8 @@ EXTERN_ENGINE
;

static bool shouldResetPid = false;
// we might reset PID state when the state is changed, but only if needed (See autoIdle())
static bool mightResetPid = false;

#if EFI_IDLE_INCREMENTAL_PID_CIC || defined(__DOXYGEN__)
// Use new PID with CIC integrator
Expand All @@ -68,6 +70,10 @@ static percent_t currentIdlePosition = -100.0f;
* the same as currentIdlePosition, but without adjustments (iacByTpsTaper, afterCrankingIACtaperDuration)
*/
static percent_t baseIdlePosition = currentIdlePosition;
/**
* When the IAC position value change is insignificant (lower than this threshold), leave the poor valve alone
*/
static percent_t idlePositionSensitivityThreshold = 1.0f;

void idleDebug(const char *msg, percent_t value) {
scheduleMsg(logger, "idle debug: %s%.2f", msg, value);
Expand Down Expand Up @@ -163,9 +169,16 @@ percent_t getIdlePosition(void) {
return currentIdlePosition;
}

static float autoIdle(float cltCorrection) {
static float autoIdle() {
percent_t tpsPos = getTPS(PASS_ENGINE_PARAMETER_SIGNATURE);
if (tpsPos > boardConfiguration->idlePidDeactivationTpsThreshold) {
// Don't store old I and D terms if PID doesn't work anymore.
// Otherwise they will affect the idle position much later, when the throttle is closed.
if (mightResetPid) {
mightResetPid = false;
shouldResetPid = true;
}

// just leave IAC position as is (but don't return currentIdlePosition - it may already contain additionalAir)
return baseIdlePosition;
}
Expand All @@ -180,7 +193,23 @@ static float autoIdle(float cltCorrection) {
targetRpm = interpolate2d("cltRpm", clt, CONFIG(cltIdleRpmBins), CONFIG(cltIdleRpm), CLT_CURVE_SIZE);
}

percent_t newValue = idlePid.getValue(targetRpm, getRpmE(engine), engineConfiguration->idleRpmPid.period);
// check if within the dead zone
int rpm = getRpmE(engine);
if (absI(rpm - targetRpm) <= CONFIG(idlePidRpmDeadZone))
return baseIdlePosition;

// When rpm < targetRpm, there's a risk of dropping RPM too low - and the engine dies out.
// So PID reaction should be increased by adding extra percent to PID-error:
percent_t errorAmpCoef = 1.0f;
if (rpm < targetRpm)
errorAmpCoef += (float)CONFIG(pidExtraForLowRpm) / PERCENT_MULT;
// If errorAmpCoef > 1.0, then PID thinks that RPM is lower than it is, and controls IAC more aggressively
idlePid.setErrorAmplification(errorAmpCoef);

percent_t newValue = idlePid.getValue(targetRpm, rpm, engineConfiguration->idleRpmPid.period);

// the state of PID has been changed, so we might reset it now, but only when needed (see idlePidDeactivationTpsThreshold)
mightResetPid = true;

#if EFI_IDLE_INCREMENTAL_PID_CIC || defined(__DOXYGEN__)
// Treat the 'newValue' as if it contains not an actual IAC position, but an incremental delta.
Expand All @@ -192,6 +221,22 @@ static float autoIdle(float cltCorrection) {
newValue = minF(newValue, CONFIG(idleRpmPid.maxValue));
#endif /* EFI_IDLE_INCREMENTAL_PID_CIC */

// Interpolate to the manual position when RPM is close to the upper RPM limit (if idlePidRpmUpperLimit is set).
// If RPM increases and the throttle is closed, then we're in coasting mode, and we should smoothly disable auto-pid.
// If we just leave IAC at baseIdlePosition (as in case of TPS deactivation threshold), RPM would get stuck.
// That's why there's 'useIacTableForCoasting' setting which involves a separate IAC position table for coasting (iacCoasting).
// Currently it's user-defined. But eventually we'll use a real calculated and stored IAC position instead.
int idlePidLowerRpm = targetRpm + CONFIG(idlePidRpmDeadZone);
if (CONFIG(idlePidRpmUpperLimit) > 0) {
if (boardConfiguration->useIacTableForCoasting) {
percent_t iacPosForCoasting = interpolate2d("iacCoasting", clt, CONFIG(iacCoastingBins), CONFIG(iacCoasting), CLT_CURVE_SIZE);
newValue = interpolateClamped(idlePidLowerRpm, newValue, idlePidLowerRpm + CONFIG(idlePidRpmUpperLimit), iacPosForCoasting, rpm);
} else {
// Well, just leave it as is, without PID regulation...
newValue = baseIdlePosition;
}
}

return newValue;
}

Expand Down Expand Up @@ -233,6 +278,7 @@ static msg_t ivThread(int param) {

float clt = engine->sensors.clt;
bool isRunning = engine->rpmCalculator.isRunning(PASS_ENGINE_PARAMETER_SIGNATURE);
// cltCorrection is used only for cranking or running in manual mode
float cltCorrection;
if (cisnan(clt))
cltCorrection = 1.0f;
Expand All @@ -259,7 +305,7 @@ static msg_t ivThread(int param) {
// let's re-apply CLT correction
iacPosition = manualIdleController(cltCorrection);
} else {
iacPosition = autoIdle(cltCorrection);
iacPosition = autoIdle();
}

// store 'base' iacPosition without adjustments
Expand All @@ -276,7 +322,8 @@ static msg_t ivThread(int param) {
engine->rpmCalculator.getRevolutionCounterSinceStart());
}

if (absF(iacPosition - currentIdlePosition) < 1) {
// The threshold is dependent on IAC type (see initIdleHardware())
if (absF(iacPosition - currentIdlePosition) < idlePositionSensitivityThreshold) {
continue; // value is pretty close, let's leave the poor valve alone
}

Expand All @@ -287,6 +334,7 @@ static msg_t ivThread(int param) {
idlePid.postState(&tsOutputChannels, 1000000);
} else {
tsOutputChannels.debugFloatField1 = iacPosition;
tsOutputChannels.debugIntField1 = iacMotor.getTargetPosition();
}
#endif
}
Expand Down Expand Up @@ -379,13 +427,16 @@ static void initIdleHardware() {
iacMotor.initialize(boardConfiguration->idle.stepperStepPin, boardConfiguration->idle.stepperDirectionPin,
engineConfiguration->stepperDirectionPinMode, engineConfiguration->idleStepperReactionTime,
engineConfiguration->idleStepperTotalSteps, engineConfiguration->stepperEnablePin, logger);
// This greatly improves PID accuracy for steppers with a small number of steps
idlePositionSensitivityThreshold = 1.0f / engineConfiguration->idleStepperTotalSteps;
} else {
/**
* Start PWM for idleValvePin
*/
startSimplePwmExt(&idleSolenoid, "Idle Valve", boardConfiguration->idle.solenoidPin, &enginePins.idleSolenoidPin,
boardConfiguration->idle.solenoidFrequency, boardConfiguration->manIdlePosition / 100,
applyIdleSolenoidPinState);
idlePositionSensitivityThreshold = 1.0f;
}
}

Expand Down
7 changes: 6 additions & 1 deletion firmware/controllers/math/pid.cpp
Expand Up @@ -39,7 +39,7 @@ float Pid::getValue(float target, float input) {
}

float Pid::getRawValue(float target, float input, float dTime) {
float error = target - input;
float error = (target - input) * errorAmplificationCoef;
prevTarget = target;
prevInput = input;

Expand Down Expand Up @@ -74,6 +74,7 @@ void Pid::updateFactors(float pFactor, float iFactor, float dFactor) {
void Pid::reset(void) {
dTerm = iTerm = 0;
prevResult = prevInput = prevTarget = prevError = 0;
errorAmplificationCoef = 1.0f;
resetCounter++;
}

Expand Down Expand Up @@ -101,6 +102,10 @@ float Pid::getOffset(void) {
return pid->offset;
}

void Pid::setErrorAmplification(float coef) {
errorAmplificationCoef = coef;
}

#if EFI_PROD_CODE || EFI_SIMULATOR
void Pid::postState(TunerStudioOutputChannels *tsOutputChannels) {
postState(tsOutputChannels, 1);
Expand Down
2 changes: 2 additions & 0 deletions firmware/controllers/math/pid.h
Expand Up @@ -41,6 +41,7 @@ class Pid {
float getOffset(void);
float getIntegration(void);
float getPrevError(void);
void setErrorAmplification(float coef);
#if EFI_PROD_CODE || EFI_SIMULATOR
void postState(TunerStudioOutputChannels *tsOutputChannels);
void postState(TunerStudioOutputChannels *tsOutputChannels, int pMult);
Expand All @@ -60,6 +61,7 @@ class Pid {
float prevTarget;
float prevInput;
float prevResult;
float errorAmplificationCoef;

private:
virtual void updateITerm(float value);
Expand Down
14 changes: 10 additions & 4 deletions firmware/integration/rusefi_config.txt
Expand Up @@ -550,7 +550,7 @@ bit is_enabled_spi_2
bit stepperForceParkingEveryRestart
bit isFasterEngineSpinUpEnabled
bit coastingFuelCutEnabled
bit unused_board_984_22
bit useIacTableForCoasting
bit unused_board_984_23
bit unused_board_984_24
bit unused_board_984_25
Expand Down Expand Up @@ -903,7 +903,13 @@ float[CRANKING_ADVANCE_CURVE_SIZE] crankingAdvance ;Optional timing advance t
int16_t coastingFuelCutTps;percent between 0 and 100;"%", 1, 0, 0, 100, 0
int16_t coastingFuelCutClt;Fuel cutoff is deactivated if CLT<threshold;"C", 1, 0, -100, 100, 0

int[774] unusedEnd;
int16_t pidExtraForLowRpm;+Increases PID reaction for RPM<target by adding extra percent to PID-error;"%", 1, 0, 0, 100, 0
int16_t unusedInt16;

float[CLT_CURVE_SIZE] iacCoastingBins;CLT-based idle position for coasting (used in Auto-PID Idle mode);"C", 1, 0, -100.0, 250.0, 2
float[CLT_CURVE_SIZE] iacCoasting; CLT-based idle position for coasting (used in Auto-PID Idle mode);"%", 1, 0, 0.0, 100.0, 2

int[741] unusedEnd;


end_struct
Expand Down Expand Up @@ -934,8 +940,8 @@ float[IAT_CURVE_SIZE] iatFuelCorr;;"%", 1, 0, 0.0, 500.0, 2
float[CRANKING_CURVE_SIZE] crankingCycleCoef;;"%", 1, 0, 0.0, 500.0, 2
float[CRANKING_CURVE_SIZE] crankingCycleBins;;"counter", 1, 0, -80.0, 170.0, 2

float[CLT_CURVE_SIZE] cltIdleCorrBins;CLT-based idle position multiplier for simple manual idle controller, or target RPM multiplier for PID-based idle;"C", 1, 0, -100.0, 250.0, 2
float[CLT_CURVE_SIZE] cltIdleCorr; CLT-based idle position multiplier for simple manual idle controller, or target RPM multiplier for PID-based idle;"%", 1, 0, 0.0, 1000.0, 2
float[CLT_CURVE_SIZE] cltIdleCorrBins;CLT-based idle position multiplier for simple manual idle controller;"C", 1, 0, -100.0, 250.0, 2
float[CLT_CURVE_SIZE] cltIdleCorr; CLT-based idle position multiplier for simple manual idle controller;"%", 1, 0, 0.0, 1000.0, 2

float[MAF_DECODING_COUNT] mafDecoding;kg/hour value.\nBy the way 2.081989116 kg/h = 1 ft�/m;"kg/hour", 1, 0, -500.0, 4000.0, 2
float[MAF_DECODING_COUNT] mafDecodingBins;; "V", 1, 0, -5.0, 150.0, 2
Expand Down
26 changes: 21 additions & 5 deletions firmware/tunerstudio/rusefi.ini
Expand Up @@ -63,7 +63,7 @@ enable2ndByteCanID = false

; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by ConfigDefinition.jar based on rusefi_config.txt Sun Mar 25 09:12:10 EDT 2018
; this section was generated automatically by ConfigDefinition.jar based on rusefi_config.txt Wed Mar 28 16:53:17 EEST 2018

pageSize = 20000
page = 1
Expand Down Expand Up @@ -312,7 +312,7 @@ page = 1
stepperForceParkingEveryRestart= bits, U32, 984, [19:19], "false", "true"
isFasterEngineSpinUpEnabled= bits, U32, 984, [20:20], "false", "true"
coastingFuelCutEnabled = bits, U32, 984, [21:21], "false", "true"
unused_board_984_22 = bits, U32, 984, [22:22], "false", "true"
useIacTableForCoasting = bits, U32, 984, [22:22], "false", "true"
unused_board_984_23 = bits, U32, 984, [23:23], "false", "true"
unused_board_984_24 = bits, U32, 984, [24:24], "false", "true"
unused_board_984_25 = bits, U32, 984, [25:25], "false", "true"
Expand Down Expand Up @@ -783,7 +783,11 @@ page = 1
coastingFuelCutRpmLow = scalar, S16, 3378, "rpm", 1, 0, 0, 5000, 0
coastingFuelCutTps = scalar, S16, 3380, "%", 1, 0, 0, 100, 0
coastingFuelCutClt = scalar, S16, 3382, "C", 1, 0, -100, 100, 0
;no TS info - skipping unusedEnd offset 3384
pidExtraForLowRpm = scalar, S16, 3384, "%", 1, 0, 0, 100, 0
;no TS info - skipping unusedInt16 offset 3386
iacCoastingBins = array, F32, 3388, [16], "C", 1, 0, -100.0, 250.0, 2
iacCoasting = array, F32, 3452, [16], "%", 1, 0, 0.0, 100.0, 2
;no TS info - skipping unusedEnd offset 3516
cltCrankingCorrBins = array, F32, 6480, [8], "C", 1, 0, -100.0, 250.0, 2
cltCrankingCorr = array, F32, 6512, [8], "%", 1, 0, 0.0, 500.0, 2
idleAdvanceBins = array, F32, 6544, [8], "RPM", 1, 0, 0.0, 18000, 2
Expand Down Expand Up @@ -897,6 +901,7 @@ page = 1
slowAdcAlpha = "ExpAverage alpha coefficient"
dizzySparkOutputPin = "This implementation makes a pulse every time one of the coils is charged, using coil dwell for pulse width. See also tachOutputPin"
crankingIACposition = "IAC position during cranking"
pidExtraForLowRpm = "Increases PID reaction for RPM<target by adding extra percent to PID-error"


; CONFIG_DEFINITION_END
Expand Down Expand Up @@ -1264,6 +1269,14 @@ fileVersion = { 20171101 }
yBins = cltIdleCorr
gauge = CLTGauge

curve = iacCoastingCurve, "Coasting IAC Position for Auto-Idle"
columnLabel = "Coolant", "Multiplier"
xAxis = -40, 120, 10
yAxis = 0, 100, 10
xBins = iacCoastingBins, coolant
yBins = iacCoasting
gauge = idleAirValvePositionGauge

curve = cltCrankingCurve, "Cranking IAC multiplier"
columnLabel = "Coolant", "Multiplier"
xAxis = -40, 120, 10
Expand Down Expand Up @@ -1799,6 +1812,7 @@ menuDialog = main
subMenu = idleAdvanceCurve, "Idle Ignition Advance", 0, {useSeparateAdvanceForIdle == 1}
subMenu = std_separator
subMenu = cltIdleCurve, "Warmup Idle multiplier"
subMenu = iacCoastingCurve, "Coasting IAC Position for Auto-Idle", 0, {useIacTableForCoasting == 1}

menu = "&Tuning"
subMenu = AccelEnrich, "Accel/Decel Enrichment/Enleanment"
Expand Down Expand Up @@ -2411,15 +2425,17 @@ cmd_stop_engine = "w\x00\x99\x00\x00"
field = "Min", idleRpmPid_minValue
field = "Max", idleRpmPid_maxValue
field = "period", idleRpmPid_period
field = "RPM dead zone to deactivate IAC pid", idlePidRpmDeadZone, { idleMode == 0}
field = "RPM upper limit to deactivate IAC pid",idlePidRpmUpperLimit, { idleMode == 0}
field = "RPM dead zone to deactivate IAC pid", idlePidRpmDeadZone
field = "RPM upper limit to deactivate IAC pid",idlePidRpmUpperLimit
field = "PID Extra for low RPM", pidExtraForLowRpm


dialog = idleSettings, "", yAxis
field = "!Automatic Mode is now Beta Version"
field = "Idle IAC control mode", idleMode
field = "Use separate Ignition Table for idle", useSeparateAdvanceForIdle
field = "Use separate VE Table for idle", useSeparateVeForIdle
field = "Use separate IAC Table For Coasting", useIacTableForCoasting, {idleMode == 0}
field = "TPS deactivation threshold", idlePidDeactivationTpsThreshold
panel = idlePidSettings, { idleMode == 0}
field = "Extra IAC if Throttle Pressed", iacByTpsTaper;
Expand Down

0 comments on commit 99ea4ee

Please sign in to comment.