@@ -177,6 +177,37 @@ 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 `` \mathbf{H_e} `` , and bounds on the estimated plant state
186+ `` \mathbf{x̂} `` , estimated process noise `` \mathbf{ŵ} `` and estimated sensor noise
187+ `` \mathbf{v̂} `` can be included in the problem. This can be useful to include physical
188+ knowledge in the soft sensor, without adding new physical sensors (e.g. a strictly positive
189+ concentration). The closed-loop performance of a predictive controller depends on the
190+ accuracy of the plant state estimate.
191+
192+ For the CSTR, we will bound the innovation term `` \mathbf{\mathbf{y}(k)-\mathbf{ŷ}(k)} `` ,
193+ and increase `` \mathbf{Q}_{int_u} `` to accelerate the estimation of the load
194+ disturbance. The rejection is slightly faster:
195+
196+ ``` @example 1
197+ estim = MovingHorizonEstimator(model, He=10, nint_u=[1, 1], σQint_u = [2, 2])
198+ estim = setconstraint!(estim, v̂min=[-1, -0.5], v̂max=[+1, +0.5])
199+ mpc_mhe = LinMPC(estim, Hp=10, Hc=2, Mwt=[1, 1], Nwt=[0.1, 0.1])
200+ mpc_mhe = setconstraint!(mpc_mhe, ymin=[45, -Inf])
201+ setstate!(model, zeros(model.nx))
202+ u, y, d = model.uop, model(), mpc_mhe.estim.model.dop
203+ initstate!(mpc_mhe, u, y, d)
204+ u_data, y_data, ry_data = test_mpc(mpc_mhe, model)
205+ plot_data(t_data, u_data, y_data, ry_data)
206+ savefig(ans, "plot3_LinMPC.svg"); nothing # hide
207+ ```
208+
209+ ![ plot3_LinMPC] ( plot3_LinMPC.svg )
210+
180211## Adding Feedforward Compensation
181212
182213Suppose that the load disturbance `` u_l `` of the last section is in fact caused by a
@@ -243,10 +274,10 @@ u, y, d = model.uop, model(), mpc_d.estim.model.dop
243274initstate!(mpc_d, u, y, d)
244275u_data, y_data, ry_data = test_mpc_d(mpc_d, model)
245276plot_data(t_data, u_data, y_data, ry_data)
246- savefig(ans, "plot3_LinMPC .svg"); nothing # hide
277+ savefig(ans, "plot4_LinMPC .svg"); nothing # hide
247278```
248279
249- ![ plot3_LinMPC ] ( plot3_LinMPC .svg)
280+ ![ plot4_LinMPC ] ( plot4_LinMPC .svg)
250281
251282Note that measured disturbances are assumed constant in the future by default but custom
252283`` \mathbf{D̂} `` predictions are possible. The same applies for the setpoint predictions
0 commit comments