diff --git a/firmware/util/math/pid.h b/firmware/util/math/pid.h index e8f990af0d..289f183acf 100644 --- a/firmware/util/math/pid.h +++ b/firmware/util/math/pid.h @@ -79,6 +79,7 @@ private: /** * A PID implementation with a modified cascaded integrator-comb (CIC) filtering. * Used for incremental auto-IAC control. See autoIdle() in idle_thread.cpp + * See pid_cic.md. * * https://rusefi.com/forum/viewtopic.php?f=9&t=1315 */ diff --git a/firmware/util/math/pid_cic.md b/firmware/util/math/pid_cic.md new file mode 100644 index 0000000000..7fc4ae9b34 --- /dev/null +++ b/firmware/util/math/pid_cic.md @@ -0,0 +1,45 @@ +*PID CIC* +A PID implementation with a modified cascaded integrator-comb (CIC) filtering. +Used for incremental auto-IAC control. See autoIdle() in idle_thread.cpp +22 Dec 2017. + +(Also see explanation in Russian here: https://rusefi.com/forum/viewtopic.php?f=9&t=1315) + +*** A bit of background *** + +@darxfame and @andreika have been experimenting with some of the PID auto-tuning methods for IAC (Ziegler etc.). +They tested the obtained coefficients on the existing ("classic") PID implementation in rusEFI and looked at what was going on using the debug logs. +It's observed that the I-term tends to exceed the min/max limits very often, especially at the initial stages of PID tuning. +This greatly distorts the results and negates the perception of the reaction of the system when selecting parameters. +In the classic PID implementation, the I-term is limited to min/max values of the PID itself. And that's by no means always acceptable, +especially for high-inertia engines and slow IAC actuators, where the integrator is highly accumulated. + +The simplest solution, proposed in the comments of the PID implementation, was to simply add separate (and extended) limits for the I-term. +But this approach has one drawback: it cannot "forget" past errors, relying on the fact that the PID is already well tuned, +and the error will inevitably decrease. However, in the case of an unconfigured PID or other reasons, +when self-oscillations of the controller appear (aka "oscillation build-up"), this does not happen. The integrator still bumps into the limits, even if extended. +But, most importantly, the errors accumulated "inside" the I-value are too old and no longer relevant to the current position of the controller. + +*** The proposal *** + +Therefore, the idea came up: to make a time window for the integrator (measured in N seconds, depending on the setting of the PID period), +and then there will be no accumulation of past non-relevant errors, and the I-term itself will be naturally limited. + +Unfortunately, we cannot afford the "straightforward" implementation of the running sum, because you will have to store all error values in a large buffer +during the entire integration window (and it can be tens of seconds). + +Therefore, a cascade integrator has been implemented - an algorithm like a CIC filter (cascaded integrator-comb), +which requires much less memory for its buffer, and at the same time allows to maintain a running sum in a rather large window. + +*** The implementation details *** + +Actually, only two cascades are currently used (to save more memory) and, accordingly, one circular buffer - +this is enough for the integration window with a width of more than 10 seconds, even for the smallest period of 10 ms. +Moreover, it occupies 32 * 4 bytes of RAM. We also use buffer averaging to smooth out the transition between buffer positions +(otherwise a "sharp" CIC can trigger PID excitation). + +The algorithm is implemented in a separate PidCic class, and thus there is a possibility to choose any of the available PID implementations - old and new. +This also allows to declare a large memory buffer (iTermBuf) only if needed - making the "classic" PID still affordable for memory-limited board configs. +Backward compatibility is also fully preserved and there will be no inconvenience for existing users. + +This algorithm has been already tested on a real car, yet the testing is still ongoing.