iacPidMultTbl + EFI_IDLE_PID_CIC + kinetis_hysteresis (#1043)

* rename EFI_IDLE_INCREMENTAL_PID_CIC -> EFI_IDLE_PID_CIC

* Impl. IacPidMultTable

* Kinetis: Trigger Comparator Hysteresis settings (+adaptive mode)
This commit is contained in:
andreika-git 2019-12-04 07:37:32 +02:00 committed by rusefi
parent 0dd517bcc7
commit 2a39c69f51
12 changed files with 120 additions and 36 deletions

View File

@ -175,7 +175,7 @@
#define EFI_IDLE_CONTROL TRUE
#endif
#define EFI_IDLE_INCREMENTAL_PID_CIC FALSE
#define EFI_IDLE_PID_CIC FALSE
/**
* Control the main power relay based on measured ignition voltage (Vbatt)
@ -336,6 +336,7 @@
#define EFI_COMP_PRIMARY_DEVICE (&COMPD3)
#define EFI_COMP_TRIGGER_CHANNEL 6 // =E7
//#define EFI_TRIGGER_DEBUG_BLINK TRUE
//#define EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS TRUE
#define LED_WARNING_BRAIN_PIN GPIOD_13

View File

@ -105,8 +105,8 @@
#undef EFI_MEMS
#define EFI_MEMS FALSE
#undef EFI_IDLE_INCREMENTAL_PID_CIC
#define EFI_IDLE_INCREMENTAL_PID_CIC TRUE
#undef EFI_IDLE_PID_CIC
#define EFI_IDLE_PID_CIC TRUE
#define RPM_LOW_THRESHOLD 8 // RPM=8 is an empirical lower sensitivity threshold of MAX9926 for 60-2
#define NO_RPM_EVENTS_TIMEOUT_SECS 5 // (RPM < 12)

View File

@ -175,7 +175,7 @@
#define EFI_IDLE_CONTROL TRUE
#endif
#define EFI_IDLE_INCREMENTAL_PID_CIC FALSE
#define EFI_IDLE_PID_CIC FALSE
/**
* Control the main power relay based on measured ignition voltage (Vbatt)

View File

@ -103,8 +103,8 @@
#undef EFI_MEMS
#define EFI_MEMS FALSE
#undef EFI_IDLE_INCREMENTAL_PID_CIC
#define EFI_IDLE_INCREMENTAL_PID_CIC TRUE
#undef EFI_IDLE_PID_CIC
#define EFI_IDLE_PID_CIC TRUE
#define RPM_LOW_THRESHOLD 8 // RPM=8 is an empirical lower sensitivity threshold of MAX9926 for 60-2
#define NO_RPM_EVENTS_TIMEOUT_SECS 5 // (RPM < 12)

View File

@ -194,7 +194,7 @@
#define EFI_IDLE_CONTROL TRUE
#endif
#define EFI_IDLE_INCREMENTAL_PID_CIC FALSE
#define EFI_IDLE_PID_CIC FALSE
/**
* Control the main power relay based on measured ignition voltage (Vbatt)

View File

@ -95,11 +95,11 @@
#ifndef EFI_IDLE_CONTROL
#if EFI_IDLE_INCREMENTAL_PID_CIC
#if EFI_IDLE_PID_CIC
extern PidCic idlePid;
#else
extern Pid idlePid;
#endif /* EFI_IDLE_INCREMENTAL_PID_CIC */
#endif /* EFI_IDLE_PID_CIC */
#endif /* EFI_IDLE_CONTROL */

View File

@ -34,6 +34,7 @@
#include "rpm_calculator.h"
#include "pwm_generator.h"
#include "idle_thread.h"
#include "engine_math.h"
#include "engine.h"
#include "periodic_task.h"
@ -58,7 +59,7 @@ static bool shouldResetPid = false;
// See automaticIdleController().
static bool mightResetPid = false;
#if EFI_IDLE_INCREMENTAL_PID_CIC
#if EFI_IDLE_PID_CIC
// Use new PID with CIC integrator
PidCic idlePid;
#else
@ -85,7 +86,7 @@ public:
};
PidWithOverrides idlePid;
#endif /* EFI_IDLE_INCREMENTAL_PID_CIC */
#endif /* EFI_IDLE_PID_CIC */
// todo: extract interface for idle valve hardware, with solenoid and stepper implementations?
static SimplePwm idleSolenoid("idle");
@ -93,6 +94,8 @@ static SimplePwm idleSolenoid("idle");
static uint32_t lastCrankingCyclesCounter = 0;
static float lastCrankingIacPosition;
static iacPidMultiplier_t iacPidMultMap("iacPidMultiplier");
/**
* When the IAC position value change is insignificant (lower than this threshold), leave the poor valve alone
* todo: why do we have this logic? is this ever useful?
@ -273,17 +276,18 @@ static percent_t automaticIdleController(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
// 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
// Apply PID Multiplier if used
if (CONFIG(useIacPidMultTable)) {
float engineLoad = getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE);
float multCoef = iacPidMultMap.getValue(rpm / RPM_1_BYTE_PACKING_MULT, engineLoad);
// PID can be completely disabled of multCoef==0, or it just works as usual if multCoef==1
newValue = interpolateClamped(0.0f, engine->engineState.idle.baseIdlePosition, 1.0f, newValue, multCoef);
}
// Apply PID Deactivation Threshold as a smooth taper for TPS transients.
percent_t tpsPos = getTPS(PASS_ENGINE_PARAMETER_SIGNATURE);
// Treat the 'newValue' as if it contains not an actual IAC position, but an incremental delta.
// So we add this delta to the base IAC position, with a smooth taper for TPS transients.
newValue = engine->engineState.idle.baseIdlePosition + interpolateClamped(0.0f, newValue, CONFIGB(idlePidDeactivationTpsThreshold), 0.0f, tpsPos);
// apply the PID limits
newValue = maxF(newValue, CONFIG(idleRpmPid.minValue));
newValue = minF(newValue, CONFIG(idleRpmPid.maxValue));
#endif /* EFI_IDLE_INCREMENTAL_PID_CIC */
// if tps==0 then PID just works as usual, or we completely disable it if tps>=threshold
newValue = interpolateClamped(0.0f, newValue, CONFIGB(idlePidDeactivationTpsThreshold), engine->engineState.idle.baseIdlePosition, tpsPos);
// 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.
@ -451,6 +455,7 @@ IdleController idleControllerInstance;
static void applyPidSettings(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
idlePid.updateFactors(engineConfiguration->idleRpmPid.pFactor, engineConfiguration->idleRpmPid.iFactor, engineConfiguration->idleRpmPid.dFactor);
iacPidMultMap.init(CONFIG(iacPidMultTable), CONFIG(iacPidMultLoadBins), CONFIG(iacPidMultRpmBins));
}
void setDefaultIdleParameters(DECLARE_CONFIG_PARAMETER_SIGNATURE) {

View File

@ -23,13 +23,36 @@ EXTERN_ENGINE
;
static Logging *logger;
static int centeredDacValue = 127;
static volatile int centeredDacValue = 127;
static volatile int toothCnt = 0;
static volatile int dacHysteresisMin = 1; // = 5V * 1/256 (8-bit DAC) = ~20mV
static volatile int dacHysteresisMax = 15; // = ~300mV
static volatile int dacHysteresisDelta = dacHysteresisMin;
static volatile int hystUpdatePeriodNumEvents = 116; // every ~1 turn of 60-2 wheel
static volatile efitick_t prevNt = 0;
// VR-sensor saturation stuff
static volatile float curVrFreqNt = 0, saturatedVrFreqNt = 0;
static const int dacNoiseDeltaMin = 1; // = 5V * 1/256 (8-bit DAC) = ~20mV
static const int dacNoiseDeltaMax = 15; // = ~300mV
// todo: interpolate between min and max depending on the signal level (adaptive hysteresis)
static const int dacNoiseDelta = dacNoiseDeltaMax;
// We want to interpolate between min and max depending on the signal level (adaptive hysteresis).
// But we don't want to measure the signal amplitude directly, so we estimate it by measuring the signal frequency:
// for VR sensors, the amplitude is inversely proportional to the tooth's 'time-width'.
// We find it by dividing the total time by the teeth count, and use the reciprocal value as signal frequency!
static void setHysteresis(COMPDriver *comp, int sign) {
// update the hysteresis threshold, but not for every tooth
#ifdef EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS
if (toothCnt++ > hystUpdatePeriodNumEvents) {
efitick_t nowNt = getTimeNowNt();
curVrFreqNt = (float)toothCnt / (float)(nowNt - prevNt);
dacHysteresisDelta = (int)efiRound(interpolateClamped(0.0f, dacHysteresisMin, saturatedVrFreqNt, dacHysteresisMax, curVrFreqNt), 1.0f);
toothCnt = 0;
prevNt = nowNt;
#ifdef TRIGGER_COMP_EXTREME_LOGGING
scheduleMsg(logger, "* f=%f d=%d", curVrFreqNt * 1000.0f, dacHysteresisDelta);
#endif /* TRIGGER_COMP_EXTREME_LOGGING */
}
#endif /* EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS */
comp_lld_set_dac_value(comp, centeredDacValue + dacHysteresisDelta * sign);
}
static void comp_shaft_callback(COMPDriver *comp) {
uint32_t status = comp_lld_get_status(comp);
@ -43,7 +66,7 @@ static void comp_shaft_callback(COMPDriver *comp) {
(engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_FALLING : SHAFT_SECONDARY_RISING);
hwHandleShaftSignal(signal);
// shift the threshold down a little bit to avoid false-triggering (threshold hysteresis)
comp_lld_set_dac_value(comp, centeredDacValue - dacNoiseDelta);
setHysteresis(comp, -1);
}
if (status & COMP_IRQ_FALLING) {
@ -51,7 +74,7 @@ static void comp_shaft_callback(COMPDriver *comp) {
(engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_RISING : SHAFT_SECONDARY_FALLING);
hwHandleShaftSignal(signal);
// shift the threshold up a little bit to avoid false-triggering (threshold hysteresis)
comp_lld_set_dac_value(comp, centeredDacValue + dacNoiseDelta);
setHysteresis(comp, 1);
}
}
@ -82,13 +105,36 @@ void turnOnTriggerInputPins(Logging *sharedLogger) {
applyNewTriggerInputPins();
}
static int getDacValue(uint8_t voltage DECLARE_ENGINE_PARAMETER_SUFFIX) {
constexpr float maxDacValue = 255.0f; // 8-bit DAC
return (int)efiRound(maxDacValue * (float)voltage * VOLTAGE_1_BYTE_PACKING_DIV / CONFIG(adcVcc), 1.0f);
}
void startTriggerInputPins(void) {
//efiAssertVoid(CUSTOM_ERR_, !isCompEnabled, "isCompEnabled");
if (isCompEnabled) {
scheduleMsg(logger, "startTIPins(): already enabled!");
return;
}
constexpr float vSensorRef = 2.5f; // 2.5V resistor divider; todo: migrate to settings?
constexpr float maxDacValue = 255.0f;
centeredDacValue = (int)efiRound(maxDacValue / engineConfiguration->adcVcc * vSensorRef, 1.0f);
centeredDacValue = getDacValue(CONFIG(triggerCompCenterVolt) PASS_ENGINE_PARAMETER_SUFFIX); // usually 2.5V resistor divider
dacHysteresisMin = getDacValue(CONFIG(triggerCompHystMin) PASS_ENGINE_PARAMETER_SUFFIX); // usually ~20mV
dacHysteresisMax = getDacValue(CONFIG(triggerCompHystMax) PASS_ENGINE_PARAMETER_SUFFIX); // usually ~300mV
dacHysteresisDelta = dacHysteresisMin;
// 20 rpm (60_2) = 1000*60/((2*60)*20) = 25 ms for 1 tooth event
float satRpm = CONFIG(triggerCompSensorSatRpm) * RPM_1_BYTE_PACKING_MULT;
hystUpdatePeriodNumEvents = getTriggerSize(); // = 116 for "60-2" trigger wheel
float saturatedToothDurationUs = 60.0f * US_PER_SECOND_F / satRpm / hystUpdatePeriodNumEvents;
saturatedVrFreqNt = 1.0f / US2NT(saturatedToothDurationUs);
scheduleMsg(logger, "startTIPins(): cDac=%d hystMin=%d hystMax=%d satRpm=%.0f satFreq*1k=%f period=%d",
centeredDacValue, dacHysteresisMin, dacHysteresisMax, satRpm, saturatedVrFreqNt * 1000.0f, hystUpdatePeriodNumEvents);
#ifdef EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS
scheduleMsg(logger, "startTIPins(): ADAPTIVE_HYSTERESIS enabled!");
#endif /* EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS */
int channel = EFI_COMP_TRIGGER_CHANNEL; // todo: use getInputCaptureChannel(hwPin);
// todo: set pin mode to default (analog/comparator)
@ -105,8 +151,13 @@ void startTriggerInputPins(void) {
}
void stopTriggerInputPins(void) {
if (!isCompEnabled)
if (!isCompEnabled) {
scheduleMsg(logger, "stopTIPins(): already disabled!");
return;
}
scheduleMsg(logger, "stopTIPins();");
compDisable(EFI_COMP_PRIMARY_DEVICE);
isCompEnabled = false;
#if 0

View File

@ -120,6 +120,8 @@ struct_no_prefix engine_configuration_s
#define PEDAL_TO_TPS_SIZE 8
#define RPM_1_BYTE_PACKING_MULT 50
#define VOLTAGE_1_BYTE_PACKING_DIV 0.02
#define FSIO_TABLE_8 8
#define FSIO_CURVE_8 8
@ -786,7 +788,7 @@ bit useSeparateAdvanceForCranking;+This activates a separate advance table for c
bit useAdvanceCorrectionsForCranking;+This enables the various ignition corrections during cranking (IAT, CLT, FSIO and PID idle).
bit useTPSAdvanceTable;+This flag allows to use TPS for ignition lookup while in Speed Density Fuel Mode
bit etbCalibrationOnStart
bit unused_1484_bit_21
bit useIacPidMultTable;+This flag allows to use a special 'PID Multiplier' table (0.0-1.0) to compensate for nonlinear nature of IAC-RPM controller
bit unused_1484_bit_22
bit unused_1484_bit_23
bit unused_1484_bit_24
@ -1085,7 +1087,12 @@ tChargeMode_e tChargeMode;
uint8_t[4] unusuedvref;
uint8_t[4] unusuedsw;
int[3] alFIn;
uint8_t[4] unusedSpiPadding3;
uint8_t triggerCompCenterVolt;+Trigger comparator center point voltage;"V", @@VOLTAGE_1_BYTE_PACKING_DIV@@, 0, 0.0, 5.1, 2
uint8_t triggerCompHystMin;+Trigger comparator hysteresis voltage (Min);"V", @@VOLTAGE_1_BYTE_PACKING_DIV@@, 0, 0.0, 5.1, 2
uint8_t triggerCompHystMax;+Trigger comparator hysteresis voltage (Max);"V", @@VOLTAGE_1_BYTE_PACKING_DIV@@, 0, 0.0, 5.1, 2
uint8_t triggerCompSensorSatRpm;+VR-sensor saturation RPM;"RPM", @@RPM_1_BYTE_PACKING_MULT@@, 0, 0.0, 12000.0, 0
pid_s idleRpmPid2
iac_pid_mult_t iacPidMultTable;

View File

@ -737,6 +737,15 @@ fileVersion = { 20190701 }
gridOrient = 250, 0, 340 ; Space 123 rotation of grid in degrees.
upDownLabel = "(RICHER)", "(LEANER)"
table = iacPidMultTbl, iacPidMultMap, "IAC PID Multiplier Table", 1
; constant, variable
xBins = iacPidMultRpmBins, RPMValue
yBins = iacPidMultLoadBins, engineLoad
zBins = iacPidMultTable
; gridHeight = 2.0
gridOrient = 250, 0, 340 ; Space 123 rotation of grid in degrees.
upDownLabel = "(Later)", "(Sooner)"
[GaugeConfigurations]
gaugeCategory = Sensors - Extra 2
@ -1157,6 +1166,8 @@ menuDialog = main
subMenu = idlehw, "Idle hardware"
subMenu = std_separator
subMenu = cltIdleRPMCurve, "Target RPM", 0, {idleMode == 0}
subMenu = iacPidMultTbl, "IAC PID Multiplier", 0, {idleMode == 0 && useIacPidMultTable == 1}
subMenu = std_separator
subMenu = idleVeCurve, "VE", 0, {useSeparateVeForIdle == 1}
subMenu = idleAdvanceCurve, "Ignition advance", 0, {useSeparateAdvanceForIdle == 1}
subMenu = std_separator
@ -1575,6 +1586,12 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
field = "Brake pedal switch", brakePedalPin
field = "A/C switch", acSwitchAdc
dialog = triggerInputComparator, "Built-in Comparator Settings (Kinetis-only)"
field = "Comparator Center Point Voltage", triggerCompCenterVolt
field = "Comparator hysteresis voltage (Min)", triggerCompHystMin
field = "Comparator hysteresis voltage (Max)", triggerCompHystMax
field = "VR-sensor saturation RPM", triggerCompSensorSatRpm
dialog = triggerInputs, "Trigger Inputs"
field = "!ECU reboot needed to apply these settings"
field = "#Cam is primary if you have cam sensor"
@ -1583,6 +1600,7 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
field = "Secondary channel", triggerInputPins2, { trigger_type != 0 && trigger_type != 8 && trigger_type != 9 && trigger_type != 18 && trigger_type != 20}
field = "Invert Secondary", invertSecondaryTriggerSignal, { trigger_type != 0 && trigger_type != 8 && trigger_type != 9 && trigger_type != 18 && trigger_type != 20}
field = "Cam Sync/VVT input", camInputs1
panel = triggerInputComparator
dialog = allPinsSensors, "Sensors"
field = "CLT ADC input", clt_adcChannel
@ -1946,6 +1964,7 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
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
field = "Use IAC PID Multiplier Table", useIacPidMultTable
dialog = idleSettings, "", yAxis

View File

@ -158,6 +158,7 @@ typedef Map3D<IGN_RPM_COUNT, IGN_TPS_COUNT, int16_t, float> ign_tps_Map3D_t;
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, float, float> fuel_Map3D_t;
typedef Map3D<BARO_CORR_SIZE, BARO_CORR_SIZE, float, float> baroCorr_Map3D_t;
typedef Map3D<PEDAL_TO_TPS_SIZE, PEDAL_TO_TPS_SIZE, uint8_t, uint8_t> pedal2tps_t;
typedef Map3D<IAC_PID_MULT_SIZE, IAC_PID_MULT_SIZE, uint8_t, uint8_t> iacPidMultiplier_t;
void setRpmBin(float array[], int size, float idleRpm, float topRpm);

View File

@ -87,7 +87,7 @@
#define EFI_ENGINE_CONTROL TRUE
#define EFI_IDLE_CONTROL TRUE
#define EFI_IDLE_INCREMENTAL_PID_CIC FALSE
#define EFI_IDLE_PID_CIC FALSE
#define EFI_MAIN_RELAY_CONTROL FALSE
#define EFI_HIP_9011 TRUE
#define EFI_CJ125 FALSE