@@ -136,81 +136,6 @@ savefig(ans, "plot4_NonLinMPC.svg"); nothing # hide
136136
137137![ plot4_NonLinMPC] ( plot4_NonLinMPC.svg )
138138
139- ## Linearizing the Model
140-
141- Nonlinear MPC are more computationally expensive than [ ` LinMPC ` ] ( @ref ) . Solving the problem
142- should always be faster than the sampling time `` T_s = 0.1 `` s for real-time operation. For
143- electronic or mechanical systems like here, this requirement is sometimes harder to achieve
144- because of their fast dynamics. To ease the design and comparison with [ ` LinMPC ` ] ( @ref ) , the
145- [ ` linearize ` ] ( @ref ) function allows automatic linearization of [ ` NonLinModel ` ] ( @ref ) based
146- on [ ` ForwardDiff.jl ` ] ( https://juliadiff.org/ForwardDiff.jl/stable/ ) . We first linearize
147- ` model ` at the operating points `` \mathbf{x} = [\begin{smallmatrix} π\\0 \end{smallmatrix}] ``
148- and `` \mathbf{u} = 0 `` (inverted position):
149-
150- ``` @example 1
151- linmodel = linearize(model, x=[π, 0], u=[0])
152- ```
153-
154- It is worth mentionning that the Euler method in ` model ` object is not the best choice for
155- linearization since its accuracy is low (i.e. approximation of a bad approximation). A
156- [ ` SteadyKalmanFilter ` ] ( @ref ) and a [ ` LinMPC ` ] ( @ref ) are designed from ` linmodel ` :
157-
158- ``` @example 1
159- kf = SteadyKalmanFilter(linmodel; σQ, σR, nint_u, σQint_u)
160- mpc = LinMPC(kf, Hp=20, Hc=2, Mwt=[0.5], Nwt=[2.5])
161- mpc = setconstraint!(mpc, umin=[-1.5], umax=[+1.5])
162- ```
163-
164- The linear controller has difficulties to reject the 10° step disturbance:
165-
166- ``` @example 1
167- res_lin = sim!(mpc, N, [180.0]; plant, x0=[π, 0], y_step=[10])
168- plot(res_lin)
169- savefig(ans, "plot5_NonLinMPC.svg"); nothing # hide
170- ```
171-
172- ![ plot5_NonLinMPC] ( plot5_NonLinMPC.svg )
173-
174- Some improvements can be achieved by solving the optimization problem of ` mpc ` with [ ` DAQP ` ] ( https://darnstrom.github.io/daqp/ )
175- optimizer instead of the default ` OSQP ` solver. It is indeed documented that ` DAQP ` can
176- perform better on small/medium dense matrices and unstable poles, which is obviously the
177- case here (the absolute value of unstable poles are greater than one).:
178-
179- ``` @example 1
180- using LinearAlgebra; poles = eigvals(linmodel.A)
181- ```
182-
183- To install it, run:
184-
185- ``` text
186- using Pkg; Pkg.add("DAQP")
187- ```
188-
189- Constructing a [ ` LinMPC ` ] ( @ref ) with ` DAQP ` :
190-
191- ``` @example 1
192- using JuMP, DAQP
193- daqp = Model(DAQP.Optimizer, add_bridges=false)
194- mpc2 = LinMPC(kf, Hp=20, Hc=2, Mwt=[0.5], Nwt=[2.5], optim=daqp)
195- mpc2 = setconstraint!(mpc, umin=[-1.5], umax=[+1.5])
196- ```
197-
198- does improve the rejection of the step disturbance:
199-
200- ``` @example 1
201- res_lin2 = sim!(mpc2, N, [180.0]; plant, x0=[π, 0], y_step=[10])
202- plot(res_lin2)
203- savefig(ans, "plot6_NonLinMPC.svg"); nothing # hide
204- ```
205-
206- ![ plot6_NonLinMPC] ( plot6_NonLinMPC.svg )
207-
208- The performance is still lower than the nonlinear controller, as expected, but computations
209- are about 2000 times faster (0.00002 s versus 0.04 s per time steps on average). Note that
210- ` linmodel ` is only valid for angular positions near 180°. Multiple linearized models and
211- controllers are required for large deviations from this operating point. This is known as
212- gain scheduling.
213-
214139## Economic Model Predictive Controller
215140
216141Economic MPC can achieve the same objective but with lower economical costs. For this case
@@ -273,10 +198,10 @@ setpoint is:
273198unset_time_limit_sec(empc.optim) # hide
274199res2_ry = sim!(empc, N, [180, 0], plant=plant2, x0=[0, 0], x̂0=[0, 0, 0])
275200plot(res2_ry)
276- savefig(ans, "plot7_NonLinMPC .svg"); nothing # hide
201+ savefig(ans, "plot5_NonLinMPC .svg"); nothing # hide
277202```
278203
279- ![ plot7_NonLinMPC ] ( plot7_NonLinMPC .svg)
204+ ![ plot5_NonLinMPC ] ( plot5_NonLinMPC .svg)
280205
281206and the energy consumption is slightly lower:
282207
@@ -293,10 +218,10 @@ Also, for a 10° step disturbance:
293218``` @example 1
294219res2_yd = sim!(empc, N, [180; 0]; plant=plant2, x0=[π, 0], x̂0=[π, 0, 0], y_step=[10, 0])
295220plot(res2_yd)
296- savefig(ans, "plot8_NonLinMPC .svg"); nothing # hide
221+ savefig(ans, "plot6_NonLinMPC .svg"); nothing # hide
297222```
298223
299- ![ plot8_NonLinMPC ] ( plot8_NonLinMPC .svg)
224+ ![ plot6_NonLinMPC ] ( plot6_NonLinMPC .svg)
300225
301226the new controller is able to recuperate more energy from the pendulum (i.e. negative work):
302227
@@ -306,3 +231,80 @@ Dict(:W_nmpc => calcW(res_yd), :W_empc => calcW(res2_yd))
306231
307232Of course, this gain is only exploitable if the motor electronic includes some kind of
308233regenerative circuitry.
234+
235+ ## Linearizing the Model
236+
237+ Nonlinear MPC are more computationally expensive than [ ` LinMPC ` ] ( @ref ) . Solving the problem
238+ should always be faster than the sampling time `` T_s = 0.1 `` s for real-time operation. This
239+ requirement is sometimes hard to meet on electronics or mechanical systems because of fast
240+ dynamics. To ease the design and comparison with [ ` LinMPC ` ] ( @ref ) , the [ ` linearize ` ] ( @ref )
241+ function allows automatic linearization of [ ` NonLinModel ` ] ( @ref ) based on [ ` ForwardDiff.jl ` ] ( https://juliadiff.org/ForwardDiff.jl/stable/ ) .
242+ We first linearize ` model ` at the point `` θ = π `` rad and `` ω = τ = 0 `` (inverted position):
243+
244+ ``` @example 1
245+ linmodel = linearize(model, x=[π, 0], u=[0])
246+ ```
247+
248+ It is worth mentioning that the Euler method in ` model ` object is not the best choice for
249+ linearization since its accuracy is low (approximation of a poor approximation). A
250+ [ ` SteadyKalmanFilter ` ] ( @ref ) and a [ ` LinMPC ` ] ( @ref ) are designed from ` linmodel ` :
251+
252+ ``` @example 1
253+ kf = SteadyKalmanFilter(linmodel; σQ, σR, nint_u, σQint_u)
254+ mpc = LinMPC(kf, Hp=20, Hc=2, Mwt=[0.5], Nwt=[2.5])
255+ mpc = setconstraint!(mpc, umin=[-1.5], umax=[+1.5])
256+ ```
257+
258+ The linear controller has difficulties to reject the 10° step disturbance:
259+
260+ ``` @example 1
261+ res_lin = sim!(mpc, N, [180.0]; plant, x0=[π, 0], y_step=[10])
262+ plot(res_lin)
263+ savefig(ans, "plot7_NonLinMPC.svg"); nothing # hide
264+ ```
265+
266+ ![ plot7_NonLinMPC] ( plot7_NonLinMPC.svg )
267+
268+ Solving the optimization problem of ` mpc ` with [ ` DAQP ` ] ( https://darnstrom.github.io/daqp/ )
269+ optimizer instead of the default ` OSQP ` solver can help here. It is indeed documented that
270+ ` DAQP ` can perform better on small/medium dense matrices and unstable poles[ ^ 1 ] , which is
271+ obviously the case here (absolute value of unstable poles are greater than one):
272+
273+ [ ^ 1 ] : Arnström, D., Bemporad, A., and Axehill, D. (2022). A dual active-set solver for
274+ embedded quadratic programming using recursive LDLᵀ updates. IEEE Trans. Autom. Contr.,
275+ 67(8). https://doi.org/doi:10.1109/TAC.2022.3176430 .
276+
277+ ``` @example 1
278+ using LinearAlgebra; poles = eigvals(linmodel.A)
279+ ```
280+
281+ To install the solver, run:
282+
283+ ``` text
284+ using Pkg; Pkg.add("DAQP")
285+ ```
286+
287+ Constructing a [ ` LinMPC ` ] ( @ref ) with ` DAQP ` :
288+
289+ ``` @example 1
290+ using JuMP, DAQP
291+ daqp = Model(DAQP.Optimizer, add_bridges=false)
292+ mpc2 = LinMPC(kf, Hp=20, Hc=2, Mwt=[0.5], Nwt=[2.5], optim=daqp)
293+ mpc2 = setconstraint!(mpc2, umin=[-1.5], umax=[+1.5])
294+ ```
295+
296+ does improve the rejection of the step disturbance:
297+
298+ ``` @example 1
299+ res_lin2 = sim!(mpc2, N, [180.0]; plant, x0=[π, 0], y_step=[10])
300+ plot(res_lin2)
301+ savefig(ans, "plot8_NonLinMPC.svg"); nothing # hide
302+ ```
303+
304+ ![ plot8_NonLinMPC] ( plot8_NonLinMPC.svg )
305+
306+ The closed-loop performance is still lower than the nonlinear controller, as expected, but
307+ computations are about 2000 times faster (0.00002 s versus 0.04 s per time steps, on
308+ average). Note that ` linmodel ` is only valid for angular positions near 180°. Multiple
309+ linearized models and controllers are required for large deviations from this operating
310+ point. This is known as gain scheduling.
0 commit comments