Skip to content

Commit ad7f9ea

Browse files
committed
doc: MovingHorizonEstimator example on the CSTR
1 parent d0ab4e1 commit ad7f9ea

File tree

1 file changed

+33
-2
lines changed

1 file changed

+33
-2
lines changed

docs/src/manual/linmpc.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

182213
Suppose 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
243274
initstate!(mpc_d, u, y, d)
244275
u_data, y_data, ry_data = test_mpc_d(mpc_d, model)
245276
plot_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

251282
Note 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

Comments
 (0)