From 34cda47a155db9ab6904b393c9f0810582714ed7 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 16 Sep 2025 15:52:26 -0400 Subject: [PATCH] doc: details on proper systems in `LinModel` extended help Also substituted $\mathbf{z}(t)$ to $\mathbf{s}(t)$ to avoid confusion with the decision variables --- docs/src/manual/nonlinmpc.md | 3 ++- src/model/linmodel.jl | 29 +++++++++++++++++------------ src/model/nonlinmodel.jl | 11 ++++++++--- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/docs/src/manual/nonlinmpc.md b/docs/src/manual/nonlinmpc.md index 92d973124..3ac196096 100644 --- a/docs/src/manual/nonlinmpc.md +++ b/docs/src/manual/nonlinmpc.md @@ -405,7 +405,8 @@ mpc_ms = LinMPC(skf; Hp, Hc, Mwt, Nwt, Cwt=Inf, transcription=MultipleShooting() mpc_ms = setconstraint!(mpc_ms, umin=[-1.5], umax=[+1.5]) ``` -Superimposing the previous disturbance rejection plot shows almost identical results: +Superimposing the previous disturbance rejection to the newer one gives almost identical +results: ```@example man_nonlin res_ms = sim!(mpc_ms, N, [180.0]; plant, x_0=[π, 0], y_step=[10]) diff --git a/src/model/linmodel.jl b/src/model/linmodel.jl index 18ddc21a8..2ca74f76a 100644 --- a/src/model/linmodel.jl +++ b/src/model/linmodel.jl @@ -74,16 +74,16 @@ The system `sys` can be continuous or discrete-time (`Ts` can be omitted for the For continuous dynamics, its state-space equations are (discrete case in Extended Help): ```math \begin{aligned} - \mathbf{ẋ}(t) &= \mathbf{A x}(t) + \mathbf{B z}(t) \\ - \mathbf{y}(t) &= \mathbf{C x}(t) + \mathbf{D z}(t) + \mathbf{ẋ}(t) &= \mathbf{A x}(t) + \mathbf{B s}(t) \\ + \mathbf{y}(t) &= \mathbf{C x}(t) + \mathbf{D s}(t) \end{aligned} ``` -with the state ``\mathbf{x}`` and output ``\mathbf{y}`` vectors. The ``\mathbf{z}`` vector +with the state ``\mathbf{x}`` and output ``\mathbf{y}`` vectors. The ``\mathbf{s}`` vector comprises the manipulated inputs ``\mathbf{u}`` and measured disturbances ``\mathbf{d}``, -in any order. `i_u` provides the indices of ``\mathbf{z}`` that are manipulated, and `i_d`, +in any order. `i_u` provides the indices of ``\mathbf{s}`` that are manipulated, and `i_d`, the measured disturbances. The constructor automatically discretizes continuous systems, resamples discrete ones if `Ts ≠ sys.Ts`, computes a new balancing and minimal state-space -realization, and separates the ``\mathbf{z}`` terms in two parts (details in Extended Help). +realization, and separates the ``\mathbf{s}`` terms in two parts (details in Extended Help). The rest of the documentation assumes discrete models since all systems end up in this form. See also [`ss`](@extref ControlSystemsBase.ss) @@ -112,8 +112,8 @@ LinModel with a sample time Ts = 0.1 s: The state-space equations are similar if `sys` is discrete-time: ```math \begin{aligned} - \mathbf{x}(k+1) &= \mathbf{A x}(k) + \mathbf{B z}(k) \\ - \mathbf{y}(k) &= \mathbf{C x}(k) + \mathbf{D z}(k) + \mathbf{x}(k+1) &= \mathbf{A x}(k) + \mathbf{B s}(k) \\ + \mathbf{y}(k) &= \mathbf{C x}(k) + \mathbf{D s}(k) \end{aligned} ``` Continuous dynamics are internally discretized using [`c2d`](@extref ControlSystemsBase.c2d) @@ -124,8 +124,7 @@ LinModel with a sample time Ts = 0.1 s: Note that the constructor transforms the system to its minimal and balancing realization using [`minreal`](@extref ControlSystemsBase.minreal) for controllability/observability. As a consequence, the final state-space representation will be presumably different from - the one provided in `sys`. It is also converted into a more practical form - (``\mathbf{D_u=0}`` because of the zero-order hold): + the one provided in `sys`. It is also converted into a more practical form: ```math \begin{aligned} \mathbf{x}(k+1) &= \mathbf{A x}(k) + \mathbf{B_u u}(k) + \mathbf{B_d d}(k) \\ @@ -133,7 +132,13 @@ LinModel with a sample time Ts = 0.1 s: \end{aligned} ``` Use the syntax [`LinModel{NT}(A, Bu, C, Bd, Dd, Ts)`](@ref) to force a specific - state-space representation. + state-space representation. + + It is assumed that ``\mathbf{D_u=0}`` (or `sys` is strictly proper) since otherwise the + resulting discrete controller is acausal by definition. Indeed, all discrete controllers + (1) sample an output ``\mathbf{y}(k)`` from the plant, (2) computes an action + ``\mathbf{u}(k)`` and (3) apply the action on the plant. There is a causality paradox + if ``\mathbf{u}(k)`` impacts ``\mathbf{y}(k)`` even before computing it. """ function LinModel( sys::StateSpace{E, NT}, @@ -194,8 +199,8 @@ end Convert to minimal realization state-space when `sys` is a transfer function. -`sys` is equal to ``\frac{\mathbf{y}(s)}{\mathbf{z}(s)}`` for continuous-time, and -``\frac{\mathbf{y}(z)}{\mathbf{z}(z)}``, for discrete-time. +`sys` is equal to ``\frac{\mathbf{y}(s)}{\mathbf{s}(s)}`` for continuous-time, and +``\frac{\mathbf{y}(z)}{\mathbf{s}(z)}``, for discrete-time. See also [`tf`](@extref ControlSystemsBase.tf) diff --git a/src/model/nonlinmodel.jl b/src/model/nonlinmodel.jl index 7b73b745e..37f0b2e0c 100644 --- a/src/model/nonlinmodel.jl +++ b/src/model/nonlinmodel.jl @@ -107,9 +107,10 @@ functions are defined as: where ``\mathbf{x}``, ``\mathbf{y}``, ``\mathbf{u}``, ``\mathbf{d}`` and ``\mathbf{p}`` are respectively the state, output, manipulated input, measured disturbance and parameter vectors. As a matter of fact, the parameter argument `p` can be any Julia objects but use a -mutable type if you want to change them later e.g.: a vector. If the dynamics is a function -of the time, simply add a measured disturbance defined as ``d(t) = t``. The functions can be -implemented in two possible ways: +mutable type if you want to change them later e.g.: a vector. + +See Extended Help if the dynamics are a function of ``t`` or ``\mathbf{u}`` appears in +``\mathbf{h}``. The functions can be implemented in two possible ways: 1. **Non-mutating functions** (out-of-place): define them as `f(x, u, d, p) -> ẋ` and `h(x, d, p) -> y`. This syntax is simple and intuitive but it allocates more memory. @@ -191,6 +192,10 @@ NonLinModel with a sample time Ts = 2.0 s: `h(x, d, p) -> y`. 2. **Mutating functions**: define them as `f!(xnext, x, u, d, p) -> nothing` and `h!(y, x, d, p) -> nothing`. + + If the dynamics are a function of the time, simply add a measured disturbance defined as + ``d(t) = t``. This package does not support the ``\mathbf{u}`` argument in ``\mathbf{h}`` + function, see the Extended Help of [`LinModel`](@ref) for the justification. """ function NonLinModel{NT}( f::Function, h::Function, Ts::Real, nu::Int, nx::Int, ny::Int, nd::Int=0;