@@ -139,13 +139,13 @@ Lastly, we plot the closed-loop test with the `Plots` package:
139139``` @example 1
140140using Plots
141141function plot_data(t_data, u_data, y_data, ry_data)
142- p1 = plot(t_data, y_data[1,:], label="meas."); ylabel!( "level")
142+ p1 = plot(t_data, y_data[1,:], label="meas.", ylabel= "level")
143143 plot!(p1, t_data, ry_data[1,:], label="setpoint", linestyle=:dash, linetype=:steppost)
144144 plot!(p1, t_data, fill(45,size(t_data)), label="min", linestyle=:dot, linewidth=1.5)
145- p2 = plot(t_data, y_data[2,:], label="meas.", legend=:topleft); ylabel!( "temp.")
145+ p2 = plot(t_data, y_data[2,:], label="meas.", legend=:topleft, ylabel= "temp.")
146146 plot!(p2, t_data, ry_data[2,:],label="setpoint", linestyle=:dash, linetype=:steppost)
147- p3 = plot(t_data,u_data[1,:],label="cold", linetype=:steppost); ylabel!( "flow rate")
148- plot!(p3, t_data,u_data[2,:],label="hot", linetype=:steppost); xlabel!( "time (s)")
147+ p3 = plot(t_data,u_data[1,:],label="cold", linetype=:steppost, ylabel= "flow rate")
148+ plot!(p3, t_data,u_data[2,:],label="hot", linetype=:steppost, xlabel= "time (s)")
149149 return plot(p1, p2, p3, layout=(3,1))
150150end
151151plot_data(t_data, u_data, y_data, ry_data)
@@ -177,11 +177,44 @@ savefig(ans, "plot2_LinMPC.svg"); nothing # hide
177177
178178![ plot2_LinMPC] ( plot2_LinMPC.svg )
179179
180+ ## Moving Horizon Estimation
181+
182+ The [ ` SteadyKalmanFilter ` ] ( @ref ) is a simple observer but it is not able to handle
183+ constraints at estimation. The [ ` MovingHorizonEstimator ` ] ( @ref ) (MHE) can improve the
184+ accuracy of the state estimate `` \mathbf{x̂} `` . It solves a quadratic optimization problem
185+ under a past time window `` H_e `` . Bounds on the estimated plant state `` \mathbf{x̂} `` ,
186+ estimated process noise `` \mathbf{ŵ} `` and estimated sensor noise `` \mathbf{v̂} `` can be
187+ included in the problem. This can be useful to add physical knowledge in the soft sensor,
188+ without adding new physical sensors (e.g. a strictly positive concentration). The
189+ closed-loop performance of any state feedback controller, like here, depends on the accuracy
190+ of the plant state estimate.
191+
192+ For the CSTR, we will bound the innovation term ``\mathbf{\mathbf{y}(k) - \mathbf{ŷ}(k)} =
193+ \mathbf{v̂}``, and increase the hot water unmeasured disturbance covariance in
194+ `` \mathbf{Q_{int_u}} `` to accelerate the estimation of the load disturbance. The rejection
195+ is slightly faster:
196+
197+ ``` @example 1
198+ estim = MovingHorizonEstimator(model, He=10, nint_u=[1, 1], σQint_u = [1, 2])
199+ estim = setconstraint!(estim, v̂min=[-1, -0.5], v̂max=[+1, +0.5])
200+ mpc_mhe = LinMPC(estim, Hp=10, Hc=2, Mwt=[1, 1], Nwt=[0.1, 0.1])
201+ mpc_mhe = setconstraint!(mpc_mhe, ymin=[45, -Inf])
202+ setstate!(model, zeros(model.nx))
203+ u, y, d = model.uop, model(), mpc_mhe.estim.model.dop
204+ initstate!(mpc_mhe, u, y, d)
205+ u_data, y_data, ry_data = test_mpc(mpc_mhe, model)
206+ plot_data(t_data, u_data, y_data, ry_data)
207+ savefig(ans, "plot3_LinMPC.svg"); nothing # hide
208+ ```
209+
210+ ![ plot3_LinMPC] ( plot3_LinMPC.svg )
211+
180212## Adding Feedforward Compensation
181213
182214Suppose that the load disturbance `` u_l `` of the last section is in fact caused by a
183- separate hot water pipe that discharges into the tank. Measuring this flow rate allows us to
184- incorporate feedforward compensation in the controller. The new plant model is:
215+ separate hot water pipe that discharges into the tank. Adding a new sensor to measure this
216+ flow rate allows us to incorporate feedforward compensation in the controller. The new plant
217+ model is:
185218
186219``` math
187220\begin{bmatrix}
@@ -243,10 +276,10 @@ u, y, d = model.uop, model(), mpc_d.estim.model.dop
243276initstate!(mpc_d, u, y, d)
244277u_data, y_data, ry_data = test_mpc_d(mpc_d, model)
245278plot_data(t_data, u_data, y_data, ry_data)
246- savefig(ans, "plot3_LinMPC .svg"); nothing # hide
279+ savefig(ans, "plot4_LinMPC .svg"); nothing # hide
247280```
248281
249- ![ plot3_LinMPC ] ( plot3_LinMPC .svg)
282+ ![ plot4_LinMPC ] ( plot4_LinMPC .svg)
250283
251284Note that measured disturbances are assumed constant in the future by default but custom
252285`` \mathbf{D̂} `` predictions are possible. The same applies for the setpoint predictions
0 commit comments