Handling of saturated integrator with anti-windeup

I want to model a saturated integrator

T\dot{u} ~ = r_\mathrm{ref}-u

in which u follows r_\mathrm{ref} but is also bounded to stay within u\in(u_\mathrm{min}, u_\mathrm{max}). To prevent windeup effects, the integrator state u should not grow above or below the limits.

One approach is to do something like this

D(u) ~ insat * (ref - u)

and then switch parameter insat in a callback between 0 and 1 depending on u, u_max and u_min.

From a ODE solver perspective, is this equivalent to defining

D(u) ~ ifelse(((u > u_max) & (ref > u)) | ((u < u_min) & (ref < u)), 0, ref - u)

with a callback, which forces rootfinding on u==u_max and u==u_min with empty affect!? Or is ifelse bad because the root-finding algo might step on both sides of the discontinuity?

Are there any other simple ways of implementing this that I am overlooking? The problem seems fairly standard in control context. For example, is there a smooth approximation of the system which is used commonly?
I looked at the LimPI implementation in ModelingToolkitStandardLibrary, but it does not seem to include any explicit handling of the discontinuity.

There is work ongoing to detect the discontinuity and handle it automatically

most people, including me (and I know what anti-windup refers to), don’t know what this means :wink:

Does it cause you an issue? I know it does sometimes, but often not. The MTKdtdlib is more or less waiting for the automatic handling of discontinuities.

2 Likes

most people, including me (and I know what anti-windup refers to), don’t know what this means :wink:

Good point, I guess the naming PT1 is somewhat standard in german control theory but not much wider. It just refers to a first order integrator which follows a reference T\dot{x}=u-x. I’ll adapt the post.

Good to know about the automatic handling. I presume the if lifting will essentially generate callbacks for that? Unfortunately, my project is not using MTK end-to-end, instead we’re using MTK to generate systems with open inputs and outputs, use Symbolics to build Julia functions and connect a potential large number of such systems together “traditionally”. Therefore I am left out on some of the more advanced MTK magic, most notably symbolic callbacks.

Does it cause you an issue? I know it does sometimes, but often not.

So far, not handling the discontinuities explicitly hasn’t led to any problems, this is what I am currently doing. Its more the abstract knowledge that the solvers typically assume continuous rhs and jacobians.

yes

modelica has the option to smooth discontinuities, saturation included. Unfortunately, it’s not obvious from the model code how it’s done

2 Likes

One way to get smoothness is to use feedback rather than placing a discrete limit on u as you have done. In Simulink they provide both options, called back-calculation and clamping, respectively. Back-calculation is simply a negative feedback gain on an error, which is the amount the signal exceeds its saturation, illustrated here

.
It does nothing when not saturated, and smoothly pushes down on u by the exceeding amount (EDIT: although still with a discontinuity when hitting the limit, see @baggepinnen). The higher the gain, the less the max error and the faster the dynamics (and stiffer the system).

ODE solvers have an analogous trade-off. DifferentialEquations.jl shows examples with non-smooth signals. Presumably adaptive solvers just approximate (say) a square wave with polynomials, using small steps to meet tolerance. The tighter the tolerance, the stiffer the system, here defined as the dynamical system composed of above “plant” plus its solver.

My interpretation is that “if lifting” is in between. You can have if within the plant dynamics or within the ODE solver which is naive to what’s going on. MTK is another layer that is more cognizant and can potentially make better decisions. (I would appreciation correction if this interpretation is wrong!)

1 Like

Back calculation does not change the fact that the derivative of a signal being integrated is discontinuous, you can see directly in the simulink diagram that the input to the integrator will have a discontinuous derivative.

Thanks, I’ll edit to correct. There’s still a sharp corner when you hit the limit, but it’s smooth both below and above.

My interpretation is that they don’t smooth discontinuities, they just know where they are. Your link shows smooth(0,if u > uMax then uMax else if u < uMin then uMin else u) which doesn’t do any smoothing since 0 is the order of differentiability: not at all. When >0 the solver can take better advantage of known order, but here all it can do is know that there can be a sharp corner and be careful about it. The alternative branch to smooth is homotopy which is aware of things like UpperLimit and LowerLimit. This probably lets them avoid extra if statements because the solver is cognizant.

It appears Modelica can do things several ways. (1) Naively using adaptive ODE solver, where corners are tight-stepped. (2) Aware of corners and degree of smoothness which may help with polynomial order and stepping. (3) High-level symbolically aware when a signal is at limit which may help avoid if statements or discrete callbacks. (As usual I could be wrong!)

I have never looked at Modelica or MTK code before. In both cases I’m super impressed that everything is readable!