rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Data Fields | Private Attributes
IdleController Class Reference

#include <idle_thread.h>

Inheritance diagram for IdleController:
Inheritance graph
[legend]
Collaboration diagram for IdleController:
Collaboration graph
[legend]

Public Types

using interface_t = IdleController
 
- Public Types inherited from IIdleController
enum class  Phase : uint8_t {
  Cranking , Idling , Coasting , CrankToIdleTaper ,
  Running
}
 

Public Member Functions

void init ()
 
float getIdlePosition (float rpm)
 
TargetInfo getTargetRpm (float clt) override
 
Phase determinePhase (float rpm, TargetInfo targetRpm, SensorResult tps, float vss, float crankingTaperFraction) override
 
float getCrankingTaperFraction (float clt) const override
 
percent_t getCrankingOpenLoop (float clt) const override
 
percent_t getRunningOpenLoop (IIdleController::Phase phase, float rpm, float clt, SensorResult tps) override
 
percent_t getOpenLoop (Phase phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction) override
 
float getIdleTimingAdjustment (float rpm) override
 
float getIdleTimingAdjustment (float rpm, float targetRpm, Phase phase)
 
float getClosedLoop (IIdleController::Phase phase, float tpsPos, float rpm, float targetRpm) override
 
void onConfigurationChange (engine_configuration_s const *previousConfig) override final
 
void onFastCallback () override final
 
void onEngineStop () override final
 
bool isIdlingOrTaper () const override
 
bool isCoastingAdvance () const override
 
Phase getCurrentPhase () const override
 
PidgetIdlePid ()
 
void updateLtit (float rpm, float clt, bool acActive, bool fan1Active, bool fan2Active, float idleIntegral)
 
void onIgnitionStateChanged (bool ignitionOn) override
 
- Public Member Functions inherited from EngineModule
virtual void initNoConfiguration ()
 
virtual void setDefaultConfiguration ()
 
virtual void onSlowCallback ()
 
virtual bool needsDelayedShutoff ()
 
virtual void onEnginePhase (float, efitick_t, angle_t, angle_t)
 

Data Fields

PidIndustrial industrialWithOverrideIdlePid
 
PidCic idleCicPid
 
- Data Fields inherited from idle_state_s
idle_state_e idleState = (idle_state_e)0
 
percent_t baseIdlePosition = (percent_t)0
 
percent_t iacByTpsTaper = (percent_t)0
 
bool mightResetPid: 1 {}
 
bool shouldResetPid: 1 {}
 
bool wasResetPid: 1 {}
 
bool mustResetPid: 1 {}
 
bool isCranking: 1 {}
 
bool isIacTableForCoasting: 1 {}
 
bool needReset: 1 {}
 
bool isInDeadZone: 1 {}
 
bool isBlipping: 1 {}
 
bool badTps: 1 {}
 
bool looksLikeRunning: 1 {}
 
bool looksLikeCoasting: 1 {}
 
bool looksLikeCrankToIdle: 1 {}
 
bool isIdleCoasting: 1 {}
 
bool isIdleClosedLoop: 1 {}
 
bool isIdling: 1 {}
 
bool unusedBit_19_16: 1 {}
 
bool unusedBit_19_17: 1 {}
 
bool unusedBit_19_18: 1 {}
 
bool unusedBit_19_19: 1 {}
 
bool unusedBit_19_20: 1 {}
 
bool unusedBit_19_21: 1 {}
 
bool unusedBit_19_22: 1 {}
 
bool unusedBit_19_23: 1 {}
 
bool unusedBit_19_24: 1 {}
 
bool unusedBit_19_25: 1 {}
 
bool unusedBit_19_26: 1 {}
 
bool unusedBit_19_27: 1 {}
 
bool unusedBit_19_28: 1 {}
 
bool unusedBit_19_29: 1 {}
 
bool unusedBit_19_30: 1 {}
 
bool unusedBit_19_31: 1 {}
 
uint16_t idleTarget = (uint16_t)0
 
uint16_t idleEntryRpm = (uint16_t)0
 
uint16_t idleExitRpm = (uint16_t)0
 
uint8_t alignmentFill_at_22 [2] = {}
 
int targetRpmByClt = (int)0
 
int targetRpmAc = (int)0
 
percent_t iacByRpmTaper = (percent_t)0
 
percent_t luaAdd = (percent_t)0
 
int m_lastTargetRpm = (int)0
 
percent_t idleClosedLoop = (percent_t)0
 
percent_t currentIdlePosition = (percent_t)0
 
uint16_t idleTargetAirmass = (uint16_t)0
 
scaled_channel< uint16_t, 100, 1 > idleTargetFlow = (uint16_t)0
 

Private Attributes

Phase m_lastPhase = Phase::Cranking
 
efitimeus_t restoreAfterPidResetTimeUs = 0
 
efitimeus_t lastTimeRunningUs = 0
 
float m_crankTaperEndTime = 0.0f
 
float m_idleTimingSoftEntryEndTime = 0.0f
 
Timer m_timeInIdlePhase
 
float m_lastAutomaticPosition = 0
 
Pid m_timingPid
 
float m_modeledFlowIdleTiming = 0
 
Biquad m_timingHpf
 

Detailed Description

Definition at line 56 of file idle_thread.h.

Member Typedef Documentation

◆ interface_t

Definition at line 59 of file idle_thread.h.

Member Function Documentation

◆ determinePhase()

IIdleController::Phase IdleController::determinePhase ( float  rpm,
IIdleController::TargetInfo  targetRpm,
SensorResult  tps,
float  vss,
float  crankingTaperFraction 
)
overridevirtual

Implements IIdleController.

Definition at line 61 of file idle_thread.cpp.

61 {
62#if EFI_SHAFT_POSITION_INPUT
64 return Phase::Cranking;
65 }
66 badTps = !tps;
67
68 if (badTps) {
69 // If the TPS has failed, assume the engine is running
70 return Phase::Running;
71 }
72
73 // if throttle pressed, we're out of the idle corner
75 return Phase::Running;
76 }
77
78 // If rpm too high (but throttle not pressed), we're coasting
79 // ALSO, if still in the cranking taper, disable coasting
80 if (rpm > targetRpm.IdleExitRpm) {
81 looksLikeCoasting = true;
82 } else if (rpm < targetRpm.IdleEntryRpm) {
83 looksLikeCoasting = false;
84 }
85
86 looksLikeCrankToIdle = crankingTaperFraction < 1;
88 return Phase::Coasting;
89 }
90
91 // If the vehicle is moving too quickly, disable CL idle
92 auto maxVss = engineConfiguration->maxIdleVss;
93 looksLikeRunning = maxVss != 0 && vss > maxVss;
94 if (looksLikeRunning) {
95 return Phase::Running;
96 }
97
98 // If still in the cranking taper, disable closed loop idle
101 }
102#endif // EFI_SHAFT_POSITION_INPUT
103
104 // If we are entering idle, and the PID settings are aggressive, it's good to make a soft entry upon entering closed loop
105 if (m_crankTaperEndTime == 0.0f) {
108 }
109
110 // No other conditions met, we are idling!
111 return Phase::Idling;
112}
FuelComputer fuelComputer
Definition engine.h:139
RpmCalculator rpmCalculator
Definition engine.h:306
float m_idleTimingSoftEntryEndTime
float m_crankTaperEndTime
bool isRunning() const
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration

Referenced by getIdlePosition().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getClosedLoop()

float IdleController::getClosedLoop ( IIdleController::Phase  phase,
float  tpsPos,
float  rpm,
float  targetRpm 
)
overridevirtual
Returns
idle valve position percentage for automatic closed loop mode

Implements IIdleController.

Definition at line 244 of file idle_thread.cpp.

244 {
245 auto idlePid = getIdlePid();
246
247 if (shouldResetPid && !wasResetPid) {
248 needReset = idlePid->getIntegration() <= 0 || mustResetPid;
249 // this is not-so valid since we have open loop first for this?
250 // we reset only if I-term is negative, because the positive I-term is good - it keeps RPM from dropping too low
251 if (needReset) {
252 idlePid->reset();
253 mustResetPid = false;
254 }
255 shouldResetPid = false;
256 wasResetPid = true;
257 }
258
259 // todo: move this to pid_s one day
262
263 efitimeus_t nowUs = getTimeNowUs();
264
266
267 if (!isIdleClosedLoop) {
268 // Don't store old I and D terms if PID doesn't work anymore.
269 // Otherwise they will affect the idle position much later, when the throttle is closed.¿
270 shouldResetPid = true;
271 mustResetPid = true;
272 idleState = TPS_THRESHOLD;
273
274 // We aren't idling, so don't apply any correction. A positive correction could inhibit a return to idle.
276 return 0;
277 }
278
279 bool acToggleJustTouched = engine->module<AcController>().unmock().timeSinceStateChange.getElapsedSeconds() < 0.5f /*second*/;
280 // check if within the dead zone
281 isInDeadZone = !acToggleJustTouched && std::abs(rpm - targetRpm) <= engineConfiguration->idlePidRpmDeadZone;
282 if (isInDeadZone) {
283 idleState = RPM_DEAD_ZONE;
284 // current RPM is close enough, no need to change anything
286 }
287
288 // When rpm < targetRpm, there's a risk of dropping RPM too low - and the engine dies out.
289 // So PID reaction should be increased by adding extra percent to PID-error:
290 percent_t errorAmpCoef = 1.0f;
291 if (rpm < targetRpm) {
292 errorAmpCoef += (float)engineConfiguration->pidExtraForLowRpm / PERCENT_MULT;
293 }
294
295 // if PID was previously reset, we store the time when it turned on back (see errorAmpCoef correction below)
296 if (wasResetPid) {
298 wasResetPid = false;
299 }
300 // increase the errorAmpCoef slowly to restore the process correctly after the PID reset
301 // todo: move restoreAfterPidResetTimeUs to idle?
302 efitimeus_t timeSincePidResetUs = nowUs - restoreAfterPidResetTimeUs;
303 // todo: add 'pidAfterResetDampingPeriodMs' setting
304 errorAmpCoef = interpolateClamped(0, 0, MS2US(/*engineConfiguration->pidAfterResetDampingPeriodMs*/1000), errorAmpCoef, timeSincePidResetUs);
305 // If errorAmpCoef > 1.0, then PID thinks that RPM is lower than it is, and controls IAC more aggressively
306 idlePid->setErrorAmplification(errorAmpCoef);
307
308 percent_t newValue = idlePid->getOutput(targetRpm, rpm, FAST_CALLBACK_PERIOD_MS / 1000.0f);
309 idleState = PID_VALUE;
310
311 // the state of PID has been changed, so we might reset it now, but only when needed (see idlePidDeactivationTpsThreshold)
312 mightResetPid = true;
313
314 // Apply PID Multiplier if used
316 float engineLoad = getFuelingLoad();
317 float multCoef = interpolate3d(
319 config->iacPidMultLoadBins, engineLoad,
321 );
322 // PID can be completely disabled of multCoef==0, or it just works as usual if multCoef==1
323 newValue = interpolateClamped(0, 0, 1, newValue, multCoef);
324 }
325
326 // Apply PID Deactivation Threshold as a smooth taper for TPS transients.
327 // if tps==0 then PID just works as usual, or we completely disable it if tps>=threshold
328 // TODO: should we just remove this? It reduces the gain if your zero throttle stop isn't perfect,
329 // which could give unstable results.
331
332 m_lastAutomaticPosition = newValue;
333 return newValue;
334}
Timer timeSinceStateChange
Definition ac_control.h:16
constexpr auto & module()
Definition engine.h:200
PidIndustrial industrialWithOverrideIdlePid
Pid * getIdlePid()
float m_lastAutomaticPosition
efitimeus_t restoreAfterPidResetTimeUs
float antiwindupFreq
Definition efi_pid.h:123
float derivativeFilterLoss
Definition efi_pid.h:124
float interpolateClamped(float x1, float y1, float x2, float y2, float x)
efitimeus_t getTimeNowUs()
Definition efitime.cpp:26
static constexpr persistent_config_s * config
float getFuelingLoad()
float percent_t
idle_state_e idleState
scaled_channel< uint8_t, 1, 10 > iacPidMultRpmBins[IAC_PID_MULT_RPM_SIZE]
scaled_channel< uint8_t, 20, 1 > iacPidMultTable[IAC_PID_MULT_SIZE][IAC_PID_MULT_SIZE]

Referenced by getIdlePosition().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCrankingOpenLoop()

float IdleController::getCrankingOpenLoop ( float  clt) const
overridevirtual

Implements IIdleController.

Definition at line 119 of file idle_thread.cpp.

119 {
120 return interpolate2d(clt, config->cltCrankingCorrBins, config->cltCrankingCorr);
121}
static CCM_OPTIONAL FunctionalSensor clt(SensorType::Clt, MS2NT(10))

Referenced by getOpenLoop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCrankingTaperFraction()

float IdleController::getCrankingTaperFraction ( float  clt) const
overridevirtual

Implements IIdleController.

Definition at line 114 of file idle_thread.cpp.

114 {
116 return (float)engine->rpmCalculator.getRevolutionCounterSinceStart() / taperDuration;
117}
uint32_t getRevolutionCounterSinceStart(void) const
uint16_t afterCrankingIACtaperDuration[CLT_CRANKING_TAPER_CURVE_SIZE]
float afterCrankingIACtaperDurationBins[CLT_CRANKING_TAPER_CURVE_SIZE]

Referenced by getIdlePosition().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCurrentPhase()

Phase IdleController::getCurrentPhase ( ) const
inlineoverridevirtual

Implements IIdleController.

Definition at line 96 of file idle_thread.h.

96 {
97 return m_lastPhase;
98 }

Referenced by LongTermIdleTrim::update().

Here is the caller graph for this function:

◆ getIdlePid()

Pid * IdleController::getIdlePid ( )
inline

Definition at line 107 of file idle_thread.h.

107 {
108 #if EFI_IDLE_PID_CIC
110 return &idleCicPid;
111 }
112 #endif /* EFI_IDLE_PID_CIC */
114 }

Referenced by applyPidSettings(), getClosedLoop(), getIdlePosition(), init(), onConfigurationChange(), and onEngineStop().

Here is the caller graph for this function:

◆ getIdlePosition()

float IdleController::getIdlePosition ( float  rpm)

Definition at line 336 of file idle_thread.cpp.

336 {
337#if EFI_SHAFT_POSITION_INPUT
338
339 // Simplify hardware CI: we borrow the idle valve controller as a PWM source for various stimulation tasks
340 // The logic in this function is solidly unit tested, so it's not necessary to re-test the particulars on real hardware.
341 #ifdef HARDWARE_CI
342 return config->cltIdleCorrTable[0][0];
343 #endif
344
345 bool useModeledFlow = engineConfiguration->modeledFlowIdle;
346
347 /*
348 * Here we have idle logic thread - actual stepper movement is implemented in a separate
349 * working thread see stepper.cpp
350 */
353
354 // On failed sensor, use 0 deg C - should give a safe highish idle
357
358 // Compute the target we're shooting for
359 auto targetRpm = getTargetRpm(clt);
360 m_lastTargetRpm = targetRpm.ClosedLoopTarget;
361
362 // Determine cranking taper (modeled flow does no taper of open loop)
363 float crankingTaper = useModeledFlow ? 1 : getCrankingTaperFraction(clt);
364
365 // Determine what operation phase we're in - idling or not
366 float vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed);
367 auto phase = determinePhase(rpm, targetRpm, tps, vehicleSpeed, crankingTaper);
368
369 // update TS flag
370 isIdling = (phase == Phase::Idling) || (phase == Phase::CrankToIdleTaper);
371
372 if (phase != m_lastPhase && phase == Phase::Idling) {
373 // Just entered idle, reset timer
374 m_timeInIdlePhase.reset();
375 }
376
377 m_lastPhase = phase;
378
380
381 // Always apply open loop correction
382 percent_t iacPosition = getOpenLoop(phase, rpm, clt, tps, crankingTaper);
383 baseIdlePosition = iacPosition;
384 // Force closed loop operation for modeled flow
385 auto idleMode = useModeledFlow ? IM_AUTO : engineConfiguration->idleMode;
386
387 // If TPS is working and automatic mode enabled, add any closed loop correction
388 if (tps.Valid && idleMode == IM_AUTO) {
389 if (useModeledFlow && phase != Phase::Idling) {
390 auto idlePid = getIdlePid();
391 idlePid->reset();
392 }
393 auto closedLoop = getClosedLoop(phase, tps.Value, rpm, targetRpm.ClosedLoopTarget);
394 idleClosedLoop = closedLoop;
395 iacPosition += closedLoop;
396 } else {
397 isIdleClosedLoop = false;
398 }
399
400 iacPosition = clampPercentValue(iacPosition);
401
402// todo: while is below disabled for unit tests?
403#if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
404
405 // see also tsOutputChannels->idlePosition
407
408
409 extern StepperMotor iacMotor;
411#endif /* EFI_TUNER_STUDIO */
412 if (useModeledFlow && phase != Phase::Cranking) {
413 float totalAirmass = 0.01 * iacPosition * engineConfiguration->idleMaximumAirmass;
414 idleTargetAirmass = totalAirmass;
415
416 bool shouldAdjustTiming = engineConfiguration->useIdleTimingPidControl && phase == Phase::Idling;
417
418 // extract hiqh frequency content to be handled by timing
419 float timingAirmass = shouldAdjustTiming ? m_timingHpf.filter(totalAirmass) : 0;
420
421 // Convert from airmass delta -> timing
423
424 // Handle the residual low frequency content with airflow
425 float idleAirmass = totalAirmass - timingAirmass;
426 float airflowKgPerH = 3.6 * 0.001 * idleAirmass * rpm / 60 * engineConfiguration->cylindersCount / 2;
427 idleTargetFlow = airflowKgPerH;
428
429 // Convert from desired flow -> idle valve position
430 float idlePos = interpolate2d(
431 airflowKgPerH,
434 );
435
436 iacPosition = idlePos;
437 }
438
439 currentIdlePosition = iacPosition;
440
441 bool acActive = engine->module<AcController>().unmock().acButtonState;
442 bool fan1Active = enginePins.fanRelay.getLogicValue();
443 bool fan2Active = enginePins.fanRelay2.getLogicValue();
444 updateLtit(rpm, clt, acActive, fan1Active, fan2Active, getIdlePid()->getIntegration());
445
446 return iacPosition;
447#else
448 return 0;
449#endif // EFI_SHAFT_POSITION_INPUT
450
451}
float filter(float input)
Definition biquad.cpp:74
TunerStudioOutputChannels outputChannels
Definition engine.h:109
RegisteredOutputPin fanRelay
Definition efi_gpio.h:86
RegisteredOutputPin fanRelay2
Definition efi_gpio.h:87
float m_modeledFlowIdleTiming
float getCrankingTaperFraction(float clt) const override
float getClosedLoop(IIdleController::Phase phase, float tpsPos, float rpm, float targetRpm) override
Phase determinePhase(float rpm, TargetInfo targetRpm, SensorResult tps, float vss, float crankingTaperFraction) override
Timer m_timeInIdlePhase
percent_t getOpenLoop(Phase phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction) override
TargetInfo getTargetRpm(float clt) override
void updateLtit(float rpm, float clt, bool acActive, bool fan1Active, bool fan2Active, float idleIntegral)
bool getLogicValue() const
Definition efi_gpio.cpp:667
float iTermMax
Definition efi_pid.h:69
float iTermMin
Definition efi_pid.h:68
void postState(pid_status_s &pidStatus) const
Definition efi_pid.cpp:144
virtual SensorResult get() const =0
static float getOrZero(SensorType type)
Definition sensor.h:83
float getTargetPosition() const
Definition stepper.cpp:14
EnginePins enginePins
Definition efi_gpio.cpp:24
static void finishIdleTestIfNeeded()
static FuncSensPair idlePos(PACK_MULT_VOLTAGE, SensorType::IdlePosition)
@ DriverThrottleIntent
percent_t currentIdlePosition
percent_t baseIdlePosition
scaled_channel< uint16_t, 100, 1 > idleTargetFlow
float cltIdleCorrTable[CLT_IDLE_TABLE_RPM_SIZE][CLT_IDLE_TABLE_CLT_SIZE]
Here is the call graph for this function:

◆ getIdleTimingAdjustment() [1/2]

float IdleController::getIdleTimingAdjustment ( float  rpm)
overridevirtual

Implements IIdleController.

Definition at line 207 of file idle_thread.cpp.

207 {
209}
float getIdleTimingAdjustment(float rpm) override

Referenced by getIdleTimingAdjustment().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getIdleTimingAdjustment() [2/2]

float IdleController::getIdleTimingAdjustment ( float  rpm,
float  targetRpm,
Phase  phase 
)

Definition at line 211 of file idle_thread.cpp.

211 {
212 // if not enabled, do nothing
214 return 0;
215 }
216
217 // If not idling, do nothing
218 if (phase != Phase::Idling) {
220 return 0;
221 }
222
224 // Use interpolation for correction taper
226 }
227
230 } else {
231 // We're now in the idle mode, and RPM is inside the Timing-PID regulator work zone!
232 return m_timingPid.getOutput(targetRpm, rpm, FAST_CALLBACK_PERIOD_MS / 1000.0f);
233 }
234}
void setErrorAmplification(float coef)
Definition efi_pid.cpp:138
virtual void reset()
Definition efi_pid.cpp:103
float getOutput(float target, float input)
Definition efi_pid.cpp:56
Here is the call graph for this function:

◆ getOpenLoop()

percent_t IdleController::getOpenLoop ( Phase  phase,
float  rpm,
float  clt,
SensorResult  tps,
float  crankingTaperFraction 
)
overridevirtual

Implements IIdleController.

Definition at line 183 of file idle_thread.cpp.

183 {
184 percent_t crankingValvePosition = getCrankingOpenLoop(clt);
185
186 isCranking = phase == Phase::Cranking;
188
189 // if we're cranking, nothing more to do.
190 if (isCranking) {
191 return crankingValvePosition;
192 }
193
194 // If coasting (and enabled), use the coasting position table instead of normal open loop
197 return interpolate2d(rpm, config->iacCoastingRpmBins, config->iacCoasting);
198 }
199
200 percent_t running = getRunningOpenLoop(phase, rpm, clt, tps);
201
202 // Interpolate between cranking and running over a short time
203 // This clamps once you fall off the end, so no explicit check for >1 required
204 return interpolateClamped(0, crankingValvePosition, 1, running, crankingTaperFraction);
205}
percent_t getCrankingOpenLoop(float clt) const override
percent_t getRunningOpenLoop(IIdleController::Phase phase, float rpm, float clt, SensorResult tps) override
running("running", SensorCategory.SENSOR_INPUTS, FieldType.INT, 892, 1.0, -1.0, -1.0, "")
scaled_channel< uint8_t, 1, 100 > iacCoastingRpmBins[CLT_CURVE_SIZE]
scaled_channel< uint8_t, 2, 1 > iacCoasting[CLT_CURVE_SIZE]

Referenced by getIdlePosition().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getRunningOpenLoop()

percent_t IdleController::getRunningOpenLoop ( IIdleController::Phase  phase,
float  rpm,
float  clt,
SensorResult  tps 
)
overridevirtual

Implements IIdleController.

Definition at line 123 of file idle_thread.cpp.

123 {
124 float running = interpolate3d(
128 );
129
130 // Now we bump it by the AC/fan amount if necessary
131 if (engine->module<AcController>().unmock().acButtonState && (phase == Phase::Idling || phase == Phase::CrankToIdleTaper)) {
133 }
134
137
138 running += luaAdd;
139
140#if EFI_ANTILAG_SYSTEM
143}
144#endif /* EFI_ANTILAG_SYSTEM */
145
146 // 'dashpot' (hold+decay) logic for coasting->idle
147 float tpsForTaper = tps.value_or(0);
148 efitimeus_t nowUs = getTimeNowUs();
149 if (phase == Phase::Running) {
150 lastTimeRunningUs = nowUs;
151 }
152 // imitate a slow pedal release for TPS taper (to avoid engine stalls)
153 if (tpsForTaper <= engineConfiguration->idlePidDeactivationTpsThreshold) {
154 // make sure the time is not zero
155 float timeSinceRunningPhaseSecs = (nowUs - lastTimeRunningUs + 1) / US_PER_SECOND_F;
156 // we shift the time to implement the hold correction (time can be negative)
157 float timeSinceRunningAfterHoldSecs = timeSinceRunningPhaseSecs - engineConfiguration->iacByTpsHoldTime;
158 // implement the decay correction (from tpsForTaper to 0)
159 tpsForTaper = interpolateClamped(0, engineConfiguration->idlePidDeactivationTpsThreshold, engineConfiguration->iacByTpsDecayTime, tpsForTaper, timeSinceRunningAfterHoldSecs);
160 }
161
162 // Now bump it by the specified amount when the throttle is opened (if configured)
163 // nb: invalid tps will make no change, no explicit check required
165 0, 0,
167 tpsForTaper);
168
170
171 float airTaperRpmUpperLimit = engineConfiguration->idlePidRpmUpperLimit;
174 airTaperRpmUpperLimit, engineConfiguration->airByRpmTaper,
175 rpm);
176
178
179 // are we clamping open loop part separately? should not we clamp once we have total value?
180 return clampPercentValue(running);
181}
AntilagSystemBase antilagController
Definition engine.h:228
efitimeus_t lastTimeRunningUs
scaled_channel< uint8_t, 1, 100 > rpmIdleCorrBins[CLT_IDLE_TABLE_RPM_SIZE]

Referenced by getOpenLoop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getTargetRpm()

IIdleController::TargetInfo IdleController::getTargetRpm ( float  clt)
overridevirtual

Implements IIdleController.

Definition at line 27 of file idle_thread.cpp.

27 {
29
30 // FIXME: this is running as "RPM target" not "RPM bump" [ie adding to the CLT rpm target]
31 // idle air Bump for AC
32 // Why do we bump based on button not based on actual A/C relay state?
33 // Because AC output has a delay to allow idle bump to happen first, so that the airflow increase gets a head start on the load increase
34 // alternator duty cycle has a similar logic
36
38 float rpmUpperLimit = engineConfiguration->idlePidRpmUpperLimit;
39 float entryRpm = target + rpmUpperLimit;
40
41 // Higher exit than entry to add some hysteresis to avoid bouncing around upper threshold
42 float exitRpm = target + 1.5 * rpmUpperLimit;
43
44 // Ramp the target down from the transition RPM to normal over a few seconds
46 // Ramp the target down from the transition RPM to normal over a few seconds
47 float timeSinceIdleEntry = m_timeInIdlePhase.getElapsedSeconds();
48 target += interpolateClamped(
49 0, rpmUpperLimit,
51 timeSinceIdleEntry
52 );
53 }
54
55 idleTarget = target;
56 idleEntryRpm = entryRpm;
57 idleExitRpm = exitRpm;
58 return { target, entryRpm, exitRpm };
59}
scaled_channel< int16_t, 1, 1 > cltIdleRpmBins[CLT_CURVE_SIZE]
scaled_channel< uint8_t, 1, 20 > cltIdleRpm[CLT_CURVE_SIZE]

Referenced by getIdlePosition().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

void IdleController::init ( )

Definition at line 473 of file idle_thread.cpp.

473 {
474 shouldResetPid = false;
475 mightResetPid = false;
476 wasResetPid = false;
481}
void configureHighpass(float samplingFrequency, float cutoffFrequency, float Q=0.54f)
Definition biquad.cpp:61
LongTermIdleTrim m_ltit
Definition engine.h:135
virtual void loadLtitFromConfig()
void initPidClass(pid_s *parameters)
Definition efi_pid.cpp:24

Referenced by startIdleThread().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isCoastingAdvance()

bool IdleController::isCoastingAdvance ( ) const
inlineoverridevirtual

Implements IIdleController.

Definition at line 92 of file idle_thread.h.

Referenced by getRunningAdvance().

Here is the caller graph for this function:

◆ isIdlingOrTaper()

bool IdleController::isIdlingOrTaper ( ) const
inlineoverridevirtual

◆ onConfigurationChange()

void IdleController::onConfigurationChange ( engine_configuration_s const *  previousConfig)
finaloverridevirtual

Reimplemented from EngineModule.

Definition at line 466 of file idle_thread.cpp.

466 {
467#if ! EFI_UNIT_TEST
468 shouldResetPid = !previousConfiguration || !getIdlePid()->isSame(&previousConfiguration->idleRpmPid);
470#endif
471}
bool isSame(const pid_s *parameters) const
Definition efi_pid.cpp:39
Here is the call graph for this function:

◆ onEngineStop()

void IdleController::onEngineStop ( )
finaloverridevirtual

Reimplemented from EngineModule.

Definition at line 462 of file idle_thread.cpp.

462 {
463 getIdlePid()->reset();
464}
Here is the call graph for this function:

◆ onFastCallback()

void IdleController::onFastCallback ( )
finaloverridevirtual

Reimplemented from EngineModule.

Definition at line 453 of file idle_thread.cpp.

453 {
454#if EFI_SHAFT_POSITION_INPUT
456 applyIACposition(position);
457 // huh: why not onIgnitionStateChanged?
459#endif // EFI_SHAFT_POSITION_INPUT
460}
TriggerCentral triggerCentral
Definition engine.h:318
InstantRpmCalculator instantRpm
void applyIACposition(percent_t position)
percent_t getIdlePosition()
Here is the call graph for this function:

◆ onIgnitionStateChanged()

void IdleController::onIgnitionStateChanged ( bool  ignitionOn)
overridevirtual

Reimplemented from EngineModule.

Definition at line 489 of file idle_thread.cpp.

489 {
491}
void onIgnitionStateChanged(bool ignitionOn)
Here is the call graph for this function:

◆ updateLtit()

void IdleController::updateLtit ( float  rpm,
float  clt,
bool  acActive,
bool  fan1Active,
bool  fan2Active,
float  idleIntegral 
)

Definition at line 483 of file idle_thread.cpp.

483 {
485 engine->m_ltit.update(rpm, clt, acActive, fan1Active, fan2Active, idleIntegral);
486 }
487}
void update(float rpm, float clt, bool acActive, bool fan1Active, bool fan2Active, float idleIntegral)

Referenced by getIdlePosition().

Here is the call graph for this function:
Here is the caller graph for this function:

Field Documentation

◆ idleCicPid

PidCic IdleController::idleCicPid

Definition at line 104 of file idle_thread.h.

Referenced by getIdlePid().

◆ industrialWithOverrideIdlePid

PidIndustrial IdleController::industrialWithOverrideIdlePid

Definition at line 100 of file idle_thread.h.

Referenced by getClosedLoop(), and getIdlePid().

◆ lastTimeRunningUs

efitimeus_t IdleController::lastTimeRunningUs = 0
private

Definition at line 125 of file idle_thread.h.

Referenced by getRunningOpenLoop().

◆ m_crankTaperEndTime

float IdleController::m_crankTaperEndTime = 0.0f
private

Definition at line 127 of file idle_thread.h.

Referenced by determinePhase(), and getIdleTimingAdjustment().

◆ m_idleTimingSoftEntryEndTime

float IdleController::m_idleTimingSoftEntryEndTime = 0.0f
private

Definition at line 128 of file idle_thread.h.

Referenced by determinePhase(), and getIdleTimingAdjustment().

◆ m_lastAutomaticPosition

float IdleController::m_lastAutomaticPosition = 0
private

Definition at line 133 of file idle_thread.h.

Referenced by getClosedLoop().

◆ m_lastPhase

Phase IdleController::m_lastPhase = Phase::Cranking
private

◆ m_modeledFlowIdleTiming

float IdleController::m_modeledFlowIdleTiming = 0
private

Definition at line 136 of file idle_thread.h.

Referenced by getIdlePosition(), and getIdleTimingAdjustment().

◆ m_timeInIdlePhase

Timer IdleController::m_timeInIdlePhase
private

Definition at line 130 of file idle_thread.h.

Referenced by getIdlePosition(), and getTargetRpm().

◆ m_timingHpf

Biquad IdleController::m_timingHpf
private

Definition at line 137 of file idle_thread.h.

Referenced by getIdlePosition(), and init().

◆ m_timingPid

Pid IdleController::m_timingPid
private

Definition at line 135 of file idle_thread.h.

Referenced by getIdleTimingAdjustment(), and init().

◆ restoreAfterPidResetTimeUs

efitimeus_t IdleController::restoreAfterPidResetTimeUs = 0
private

Definition at line 123 of file idle_thread.h.

Referenced by getClosedLoop().


The documentation for this class was generated from the following files: