Skip to content

Commit b20cb53

Browse files
authored
Merge pull request #28 from JuliaControl/mhe_manual
Added a MHE example on the CSTR in the manual
2 parents d0ab4e1 + 875a251 commit b20cb53

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

docs/src/manual/linmpc.md

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,13 @@ Lastly, we plot the closed-loop test with the `Plots` package:
139139
```@example 1
140140
using Plots
141141
function 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))
150150
end
151151
plot_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

182214
Suppose 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
243276
initstate!(mpc_d, u, y, d)
244277
u_data, y_data, ry_data = test_mpc_d(mpc_d, model)
245278
plot_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

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

Comments
 (0)