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 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_18_15: 1 {}
 
bool unusedBit_18_16: 1 {}
 
bool unusedBit_18_17: 1 {}
 
bool unusedBit_18_18: 1 {}
 
bool unusedBit_18_19: 1 {}
 
bool unusedBit_18_20: 1 {}
 
bool unusedBit_18_21: 1 {}
 
bool unusedBit_18_22: 1 {}
 
bool unusedBit_18_23: 1 {}
 
bool unusedBit_18_24: 1 {}
 
bool unusedBit_18_25: 1 {}
 
bool unusedBit_18_26: 1 {}
 
bool unusedBit_18_27: 1 {}
 
bool unusedBit_18_28: 1 {}
 
bool unusedBit_18_29: 1 {}
 
bool unusedBit_18_30: 1 {}
 
bool unusedBit_18_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 253 of file idle_thread.cpp.

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

343 {
344#if EFI_SHAFT_POSITION_INPUT
345
346 // Simplify hardware CI: we borrow the idle valve controller as a PWM source for various stimulation tasks
347 // The logic in this function is solidly unit tested, so it's not necessary to re-test the particulars on real hardware.
348 #ifdef HARDWARE_CI
349 return config->cltIdleCorrTable[0][0];
350 #endif
351
352 bool useModeledFlow = engineConfiguration->modeledFlowIdle;
353
354 /*
355 * Here we have idle logic thread - actual stepper movement is implemented in a separate
356 * working thread see stepper.cpp
357 */
360
361 // On failed sensor, use 0 deg C - should give a safe highish idle
364
365 // Compute the target we're shooting for
366 auto targetRpm = getTargetRpm(clt);
367 m_lastTargetRpm = targetRpm.ClosedLoopTarget;
368
369 // Determine cranking taper (modeled flow does no taper of open loop)
370 float crankingTaper = useModeledFlow ? 1 : getCrankingTaperFraction(clt);
371
372 // Determine what operation phase we're in - idling or not
373 float vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed);
374 auto phase = determinePhase(rpm, targetRpm, tps, vehicleSpeed, crankingTaper);
375
376 // update TS flag
377 isIdling = (phase == Phase::Idling) || (phase == Phase::CrankToIdleTaper);
378
379 if (phase != m_lastPhase && phase == Phase::Idling) {
380 // Just entered idle, reset timer
381 m_timeInIdlePhase.reset();
382 }
383
384 m_lastPhase = phase;
385
387
388 // Always apply open loop correction
389 percent_t iacPosition = getOpenLoop(phase, rpm, clt, tps, crankingTaper);
390 baseIdlePosition = iacPosition;
391 // Force closed loop operation for modeled flow
392 auto idleMode = useModeledFlow ? IM_AUTO : engineConfiguration->idleMode;
393
394 // If TPS is working and automatic mode enabled, add any closed loop correction
395 if (tps.Valid && idleMode == IM_AUTO) {
396 if (useModeledFlow && phase != Phase::Idling) {
397 auto idlePid = getIdlePid();
398 idlePid->reset();
399 }
400 auto closedLoop = getClosedLoop(phase, tps.Value, rpm, targetRpm.ClosedLoopTarget);
401 idleClosedLoop = closedLoop;
402 iacPosition += closedLoop;
403 } else {
404 isIdleClosedLoop = false;
405 }
406
407 iacPosition = clampPercentValue(iacPosition);
408
409// todo: while is below disabled for unit tests?
410#if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
411
412 // see also tsOutputChannels->idlePosition
414
415
416 extern StepperMotor iacMotor;
418#endif /* EFI_TUNER_STUDIO */
419 if (useModeledFlow && phase != Phase::Cranking) {
420 float totalAirmass = 0.01 * iacPosition * engineConfiguration->idleMaximumAirmass;
421 idleTargetAirmass = totalAirmass;
422
423 bool shouldAdjustTiming = engineConfiguration->useIdleTimingPidControl && phase == Phase::Idling;
424
425 // extract hiqh frequency content to be handled by timing
426 float timingAirmass = shouldAdjustTiming ? m_timingHpf.filter(totalAirmass) : 0;
427
428 // Convert from airmass delta -> timing
430
431 // Handle the residual low frequency content with airflow
432 float idleAirmass = totalAirmass - timingAirmass;
433 float airflowKgPerH = 3.6 * 0.001 * idleAirmass * rpm / 60 * engineConfiguration->cylindersCount / 2;
434 idleTargetFlow = airflowKgPerH;
435
436 // Convert from desired flow -> idle valve position
437 float idlePos = interpolate2d(
438 airflowKgPerH,
441 );
442
443 iacPosition = idlePos;
444 }
445
446 currentIdlePosition = iacPosition;
447
448 bool acActive = engine->module<AcController>().unmock().acButtonState;
449 bool fan1Active = enginePins.fanRelay.getLogicValue();
450 bool fan2Active = enginePins.fanRelay2.getLogicValue();
451 updateLtit(rpm, clt, acActive, fan1Active, fan2Active, getIdlePid()->getIntegration());
452
453 return iacPosition;
454#else
455 return 0;
456#endif // EFI_SHAFT_POSITION_INPUT
457
458}
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 216 of file idle_thread.cpp.

216 {
218}
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 220 of file idle_thread.cpp.

220 {
221 // if not enabled, do nothing
223 return 0;
224 }
225
226 // If not idling, do nothing
227 if (phase != Phase::Idling) {
229 return 0;
230 }
231
233 // Use interpolation for correction taper
235 }
236
239 } else {
240 // We're now in the idle mode, and RPM is inside the Timing-PID regulator work zone!
241 return m_timingPid.getOutput(targetRpm, rpm, FAST_CALLBACK_PERIOD_MS / 1000.0f);
242 }
243}
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 percent_t coastingPosition = interpolate2d(rpm, config->iacCoastingRpmBins, config->iacCoasting);
198
199 // Add A/C offset if the A/C is on during coasting
200 if (engine->module<AcController>().unmock().acButtonState) {
201 coastingPosition += engineConfiguration->acIdleExtraOffset;
202 }
203
204 // We return here, bypassing the final interpolation, so we should clamp the value
205 // to ensure it's a valid percentage.
206 return clampPercentValue(coastingPosition);
207 }
208
209 percent_t running = getRunningOpenLoop(phase, rpm, clt, tps);
210
211 // Interpolate between cranking and running over a short time
212 // This clamps once you fall off the end, so no explicit check for >1 required
213 return interpolateClamped(0, crankingValvePosition, 1, running, crankingTaperFraction);
214}
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, 888, 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 479 of file idle_thread.cpp.

479 {
480 shouldResetPid = false;
481 mightResetPid = false;
482 wasResetPid = false;
487}
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 473 of file idle_thread.cpp.

473 {
474#if ! EFI_UNIT_TEST
475 shouldResetPid = !previousConfiguration || !getIdlePid()->isSame(&previousConfiguration->idleRpmPid);
476#endif
477}
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 469 of file idle_thread.cpp.

469 {
470 getIdlePid()->reset();
471}
Here is the call graph for this function:

◆ onFastCallback()

void IdleController::onFastCallback ( )
finaloverridevirtual

Reimplemented from EngineModule.

Definition at line 460 of file idle_thread.cpp.

460 {
461#if EFI_SHAFT_POSITION_INPUT
463 applyIACposition(position);
464 // huh: why not onIgnitionStateChanged?
466#endif // EFI_SHAFT_POSITION_INPUT
467}
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 495 of file idle_thread.cpp.

495 {
497}
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 489 of file idle_thread.cpp.

489 {
491 engine->m_ltit.update(rpm, clt, acActive, fan1Active, fan2Active, idleIntegral);
492 }
493}
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: