96 lines
3.0 KiB
C
96 lines
3.0 KiB
C
/**
|
|
* @file idle_controller.c
|
|
* @brief Simple Idle Air Valve control algorithm
|
|
*
|
|
* This algorithm is trying to get current RPM to the desired 'target' value
|
|
* by changing Idle Air Valve solenoid duty cycle. Depending on how far current RPM
|
|
* is from the target RPM, the incremental change would be smaller or bigger.
|
|
*
|
|
*
|
|
* todo: DEFAULT_IDLE_DUTY should be a field on the IdleValveState, not a constant
|
|
*
|
|
* @date May 22, 2013
|
|
* @author Andrey Belomutskiy, (c) 2012-2014
|
|
*/
|
|
|
|
#include "idle_controller.h"
|
|
#include "efilib.h"
|
|
|
|
// todo: move this to "idle_controller.h"
|
|
int isCranking(void);
|
|
|
|
static int lastGoodValue = DEFAULT_IDLE_DUTY;
|
|
|
|
void idleInit(IdleValveState *idle) {
|
|
idle->value = DEFAULT_IDLE_DUTY;
|
|
setIdleRpm(idle, DEFAULT_TARGET_RPM);
|
|
idle->timeOfLastIdleChange = 0;
|
|
}
|
|
|
|
void setIdleRpm(IdleValveState *idle, int targetRpm) {
|
|
idle->targetRpmRangeLeft = (int)(targetRpm * 0.93);
|
|
idle->targetRpmRangeRight = (int)(targetRpm * 1.07);
|
|
}
|
|
|
|
/**
|
|
* @brief sets new idle valve duty cycle: checks the bounds and reports new value
|
|
*/
|
|
static int setNewValue(IdleValveState *idle, int currentRpm, int now, char * msg, int newValue) {
|
|
newValue = maxI(newValue, MIN_IDLE);
|
|
newValue = minI(newValue, MAX_IDLE);
|
|
|
|
if (idle->value != newValue) {
|
|
idleDebug(msg, currentRpm);
|
|
idle->timeOfLastIdleChange = now;
|
|
}
|
|
|
|
idle->value = newValue;
|
|
return newValue;
|
|
}
|
|
|
|
static int changeValue(IdleValveState *idle, int currentRpm, int now, char * msg, int delta) {
|
|
int newValue = idle->value + delta;
|
|
return setNewValue(idle, currentRpm, now, msg, newValue);
|
|
}
|
|
|
|
/**
|
|
* now - current time in seconds
|
|
*/
|
|
int getIdle(IdleValveState *idle, int currentRpm, int now) {
|
|
if (currentRpm == 0 || isCranking()) {
|
|
return setNewValue(idle, currentRpm, now, "cranking value: ", DEFAULT_IDLE_DUTY);
|
|
}
|
|
|
|
if (currentRpm < 0.7 * idle->targetRpmRangeLeft) {
|
|
return setNewValue(idle, currentRpm, now, "RPMs are seriously low: ", lastGoodValue);
|
|
}
|
|
|
|
if (now - idle->timeOfLastIdleChange < IDLE_PERIOD) {
|
|
// too soon to adjust anything - exiting
|
|
return idle->value;
|
|
}
|
|
|
|
if (currentRpm > idle->targetRpmRangeLeft && currentRpm < idle->targetRpmRangeRight) {
|
|
// current RPM is good enough
|
|
// todo: need idle signal input
|
|
//lastGoodValue = idle->value;
|
|
return idle->value;
|
|
}
|
|
|
|
if (currentRpm >= idle->targetRpmRangeRight + 100)
|
|
return changeValue(idle, currentRpm, now, "idle control: rpm is too high: ", -IDLE_DECREASE_STEP);
|
|
|
|
if (currentRpm >= idle->targetRpmRangeRight)
|
|
return changeValue(idle, currentRpm, now, "idle control: rpm is a bit too high: ", -1);
|
|
|
|
// we are here if RPM is low, let's see how low
|
|
// if (currentRpm < 0.7 * idle->targetRpmRangeLeft) {
|
|
// // todo: act faster in case of really low RPM?
|
|
// return setNewValue(idle, currentRpm, now, "RPMs are seriously low: ", 15 * IDLE_INCREASE_STEP);
|
|
// } else
|
|
if (currentRpm < idle->targetRpmRangeLeft - 100) {
|
|
return changeValue(idle, currentRpm, now, "idle control: RPMs are low: ", IDLE_INCREASE_STEP);
|
|
}
|
|
return changeValue(idle, currentRpm, now, "idle control: RPMs are a bit low: ", 1);
|
|
}
|