From 2a39c69f518ff44c34bbf83b7f7f213394b74c2b Mon Sep 17 00:00:00 2001 From: andreika-git Date: Wed, 4 Dec 2019 07:37:32 +0200 Subject: [PATCH] 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) --- firmware/config/boards/kinetis/efifeatures.h | 3 +- .../config/boards/prometheus/efifeatures.h | 4 +- firmware/config/boards/skeleton/efifeatures.h | 2 +- .../config/boards/subaru-ej20gn/efifeatures.h | 4 +- firmware/config/stm32f4ems/efifeatures.h | 2 +- firmware/console/binary/tunerstudio.cpp | 4 +- .../controllers/actuators/idle_thread.cpp | 29 ++++--- firmware/hw_layer/trigger_input_comp.cpp | 75 ++++++++++++++++--- firmware/integration/rusefi_config.txt | 11 ++- firmware/tunerstudio/rusefi.input | 19 +++++ firmware/util/containers/table_helper.h | 1 + simulator/simulator/efifeatures.h | 2 +- 12 files changed, 120 insertions(+), 36 deletions(-) diff --git a/firmware/config/boards/kinetis/efifeatures.h b/firmware/config/boards/kinetis/efifeatures.h index 456d22aba1..fb8aadb692 100644 --- a/firmware/config/boards/kinetis/efifeatures.h +++ b/firmware/config/boards/kinetis/efifeatures.h @@ -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 diff --git a/firmware/config/boards/prometheus/efifeatures.h b/firmware/config/boards/prometheus/efifeatures.h index 3d39906559..ecf7eba807 100644 --- a/firmware/config/boards/prometheus/efifeatures.h +++ b/firmware/config/boards/prometheus/efifeatures.h @@ -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) diff --git a/firmware/config/boards/skeleton/efifeatures.h b/firmware/config/boards/skeleton/efifeatures.h index a401d05fad..127b11c234 100644 --- a/firmware/config/boards/skeleton/efifeatures.h +++ b/firmware/config/boards/skeleton/efifeatures.h @@ -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) diff --git a/firmware/config/boards/subaru-ej20gn/efifeatures.h b/firmware/config/boards/subaru-ej20gn/efifeatures.h index d92dd2db2e..93e09ab7cc 100644 --- a/firmware/config/boards/subaru-ej20gn/efifeatures.h +++ b/firmware/config/boards/subaru-ej20gn/efifeatures.h @@ -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) diff --git a/firmware/config/stm32f4ems/efifeatures.h b/firmware/config/stm32f4ems/efifeatures.h index 4ee9074219..ca8d451104 100644 --- a/firmware/config/stm32f4ems/efifeatures.h +++ b/firmware/config/stm32f4ems/efifeatures.h @@ -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) diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index 52a426c2e7..8dc37b6138 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -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 */ diff --git a/firmware/controllers/actuators/idle_thread.cpp b/firmware/controllers/actuators/idle_thread.cpp index f635a2a77e..f2991404eb 100644 --- a/firmware/controllers/actuators/idle_thread.cpp +++ b/firmware/controllers/actuators/idle_thread.cpp @@ -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) { diff --git a/firmware/hw_layer/trigger_input_comp.cpp b/firmware/hw_layer/trigger_input_comp.cpp index 8b8b7c0427..ea2eeb6463 100644 --- a/firmware/hw_layer/trigger_input_comp.cpp +++ b/firmware/hw_layer/trigger_input_comp.cpp @@ -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 diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index c6c4f60997..8ca5d0e362 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -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; diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index c9bfde1686..edf9d3b52b 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -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 diff --git a/firmware/util/containers/table_helper.h b/firmware/util/containers/table_helper.h index a8e13d387c..d3f29a82d1 100644 --- a/firmware/util/containers/table_helper.h +++ b/firmware/util/containers/table_helper.h @@ -158,6 +158,7 @@ typedef Map3D ign_tps_Map3D_t; typedef Map3D fuel_Map3D_t; typedef Map3D baroCorr_Map3D_t; typedef Map3D pedal2tps_t; +typedef Map3D iacPidMultiplier_t; void setRpmBin(float array[], int size, float idleRpm, float topRpm); diff --git a/simulator/simulator/efifeatures.h b/simulator/simulator/efifeatures.h index fe40bc75ec..6068eab592 100644 --- a/simulator/simulator/efifeatures.h +++ b/simulator/simulator/efifeatures.h @@ -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