Skip to content

Commit e4176a5

Browse files
committed
combine plant and estimator states in plot if same model
1 parent 32135e8 commit e4176a5

File tree

5 files changed

+57
-39
lines changed

5 files changed

+57
-39
lines changed

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ using Pkg; Pkg.add("ModelPredictiveControl")
2828
### Model Predictive Control Features
2929

3030
- ✅ linear and nonlinear plant models exploiting multiple dispatch
31-
- ✅ model predictive controllers based on:
32-
- ✅ linear plant models
33-
- ✅ nonlinear plant models
3431
- ✅ supported objective function terms:
3532
- ✅ output setpoint tracking
3633
- ✅ move suppression

docs/src/index.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ Pages = [
3333
### Model Predictive Control Features
3434

3535
- ✅ linear and nonlinear plant models exploiting multiple dispatch
36-
- ✅ model predictive controllers based on:
37-
- ✅ linear plant models
38-
- ✅ nonlinear plant models
3936
- ✅ supported objective function terms:
4037
- ✅ output setpoint tracking
4138
- ✅ move suppression

example/juMPC.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,18 @@ psM = plot(resM)
159159
display(psM)
160160

161161
res = sim!(mpc, mpc.Hp+10)
162-
ps = plot(res)
162+
ps = plot(res, plotx=true)
163163
display(ps)
164164

165165
res2 = sim!(uscKalmanFilter1, mpc.Hp+10)
166166
ps2 = plot(res2)
167167
display(ps2)
168168

169+
res2 = sim!(uscKalmanFilter1, mpc.Hp+10, plant=deepcopy(uscKalmanFilter1.model))
170+
ps2 = plot(res2, plotx=true, plotx̂=true)
171+
display(ps2)
172+
173+
169174
#=
170175
test_mpc(linModel4, nmpc)
171176
@time u_data, y_data, r_data, d_data = test_mpc(linModel4, nmpc)

src/plot_sim.jl

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
"Includes all signals of [`sim!`](@ref), view them with `plot` on `SimResult` instances."
22
struct SimResult{O<:Union{SimModel, StateEstimator, PredictiveController}}
3-
T_data ::Vector{Float64} # time in seconds
4-
Y_data ::Matrix{Float64} # plant outputs (both measured and unmeasured)
5-
Ry_data::Matrix{Float64} # output setpoints
6-
Ŷ_data ::Matrix{Float64} # estimated outputs
7-
U_data ::Matrix{Float64} # manipulated inputs
8-
Ud_data::Matrix{Float64} # manipulated inputs including load disturbances
9-
D_data ::Matrix{Float64} # measured disturbances
10-
X_data ::Matrix{Float64} # plant states
11-
X̂_data ::Matrix{Float64} # estimated states
12-
obj ::O # simulated instance
3+
T_data ::Vector{Float64} # time in seconds
4+
Y_data ::Matrix{Float64} # plant outputs (both measured and unmeasured)
5+
Ry_data::Matrix{Float64} # output setpoints
6+
Ŷ_data ::Matrix{Float64} # estimated outputs
7+
U_data ::Matrix{Float64} # manipulated inputs
8+
Ud_data::Matrix{Float64} # manipulated inputs including load disturbances
9+
D_data ::Matrix{Float64} # measured disturbances
10+
X_data ::Matrix{Float64} # plant states
11+
X̂_data ::Matrix{Float64} # estimated states
12+
plantIsModel::Bool # true if simulated plant is identical to estimation model
13+
obj::O # simulated instance
1314
end
1415

1516
@doc raw"""
@@ -55,7 +56,7 @@ function sim!(
5556
updatestate!(plant, u, d);
5657
end
5758
return SimResult(
58-
T_data, Y_data, U_data, Y_data, U_data, U_data, D_data, X_data, X_data, plant
59+
T_data, Y_data, U_data, Y_data, U_data, U_data, D_data, X_data, X_data, true, plant
5960
)
6061
end
6162

@@ -96,7 +97,7 @@ vectors. The simulated sensor and process noises of `plant` are specified by `y_
9697
```julia-repl
9798
julia> model = LinModel(tf(3, [30, 1]), 0.5);
9899
99-
julia> estim = SteadyKalmanFilter(model, σR=[0.5], σQ=[0.25], σQ_int=[0.01]);
100+
julia> estim = KalmanFilter(model, σR=[0.5], σQ=[0.25], σQ_int=[0.01], σP0_int=[0.1]);
100101
101102
julia> res = sim!(estim, 50, [0], y_noise=[0.5], x_noise=[0.25], x0=[-10], x̂0=[0, 0]);
102103
@@ -170,6 +171,7 @@ function sim_closedloop!(
170171
lastu = plant.uop,
171172
)
172173
model = estim.model
174+
plantIsModel = (plant === model)
173175
model.Ts plant.Ts || error("Sampling time of controller/estimator ≠ plant.Ts")
174176
old_x0 = copy(plant.x)
175177
T_data = collect(plant.Ts*(0:(N-1)))
@@ -207,7 +209,9 @@ function sim_closedloop!(
207209
updatestate!(est_mpc, u, ym, d)
208210
end
209211
res = SimResult(
210-
T_data, Y_data, U_Ry_data, Ŷ_data, U_data, Ud_data, D_data, X_data, X̂_data, est_mpc
212+
T_data, Y_data, U_Ry_data, Ŷ_data,
213+
U_data, Ud_data, D_data, X_data, X̂_data,
214+
plantIsModel, est_mpc
211215
)
212216
setstate!(plant, old_x0)
213217
return res
@@ -304,6 +308,7 @@ end
304308
plotx̂ = false
305309
)
306310
t = res.T_data
311+
plantIsModel = res.plantIsModel
307312
ny = size(res.Y_data, 1)
308313
nu = size(res.U_data, 1)
309314
nd = size(res.D_data, 1)
@@ -312,8 +317,14 @@ end
312317
layout_mat = [(ny, 1)]
313318
plotu && (layout_mat = [layout_mat (nu, 1)])
314319
(plotd && nd 0) && (layout_mat = [layout_mat (nd, 1)])
315-
plotx && (layout_mat = [layout_mat (nx, 1)])
316-
plotx̂ && (layout_mat = [layout_mat (nx̂, 1)])
320+
if plantIsModel && plotx && !plotx̂
321+
layout_mat = [layout_mat (nx, 1)]
322+
elseif plantIsModel && plotx̂
323+
layout_mat = [layout_mat (nx̂, 1)]
324+
elseif !plantIsModel
325+
plotx && (layout_mat = [layout_mat (nx, 1)])
326+
plotx̂ && (layout_mat = [layout_mat (nx̂, 1)])
327+
end
317328
layout := layout_mat
318329
xguide --> "Time (s)"
319330
# --- outputs y ---
@@ -369,6 +380,7 @@ end
369380
t, res.D_data[i, :]
370381
end
371382
end
383+
subplot_base += nd
372384
end
373385
# --- plant states x ---
374386
if plotx
@@ -382,19 +394,20 @@ end
382394
t, res.X_data[i, :]
383395
end
384396
end
385-
subplot_base += nx
397+
!plantIsModel && (subplot_base += nx)
386398
end
387399
# --- estimated states x̂ ---
388400
if plotx̂
389401
for i in 1:nx̂
390402
@series begin
391-
yguide --> "\$\\hat{x}_$i\$"
403+
withPlantState = plantIsModel && plotx && i nx
404+
yguide --> (withPlantState ? "\$x_$i\$" : "\$\\hat{x}_$i\$")
392405
color --> 2
393406
subplot --> subplot_base + i
394407
linestyle --> :dashdot
395408
linewidth --> 0.75
396409
label --> "\$\\mathbf{\\hat{x}}\$"
397-
legend --> false
410+
legend --> (withPlantState ? true : false)
398411
t, res.X̂_data[i, :]
399412
end
400413
end
@@ -417,8 +430,8 @@ end
417430
plotx̂ = false
418431
)
419432
mpc = res.obj
420-
421433
t = res.T_data
434+
plantIsModel = res.plantIsModel
422435
ny = size(res.Y_data, 1)
423436
nu = size(res.U_data, 1)
424437
nd = size(res.D_data, 1)
@@ -427,12 +440,16 @@ end
427440
layout_mat = [(ny, 1)]
428441
plotu && (layout_mat = [layout_mat (nu, 1)])
429442
(plotd && nd 0) && (layout_mat = [layout_mat (nd, 1)])
430-
plotx && (layout_mat = [layout_mat (nx, 1)])
431-
plotx̂ && (layout_mat = [layout_mat (nx̂, 1)])
432-
443+
if plantIsModel && plotx && !plotx̂
444+
layout_mat = [layout_mat (nx, 1)]
445+
elseif plantIsModel && plotx̂
446+
layout_mat = [layout_mat (nx̂, 1)]
447+
elseif !plantIsModel
448+
plotx && (layout_mat = [layout_mat (nx, 1)])
449+
plotx̂ && (layout_mat = [layout_mat (nx̂, 1)])
450+
end
433451
layout := layout_mat
434452
xguide --> "Time (s)"
435-
436453
# --- outputs y ---
437454
subplot_base = 0
438455
for i in 1:ny
@@ -475,7 +492,7 @@ end
475492
color --> 4
476493
subplot --> subplot_base + i
477494
linestyle --> :dot
478-
linewidth --> 2.0
495+
linewidth --> 1.5
479496
label --> "\$\\mathbf{\\hat{y}_{min}}\$"
480497
legend --> true
481498
t, fill(mpc.con.Ŷmin[i], length(t))
@@ -487,7 +504,7 @@ end
487504
color --> 5
488505
subplot --> subplot_base + i
489506
linestyle --> :dot
490-
linewidth --> 2.0
507+
linewidth --> 1.5
491508
label --> "\$\\mathbf{\\hat{y}_{max}}\$"
492509
legend --> true
493510
t, fill(mpc.con.Ŷmax[i], length(t))
@@ -525,7 +542,7 @@ end
525542
color --> 4
526543
subplot --> subplot_base + i
527544
linestyle --> :dot
528-
linewidth --> 2.0
545+
linewidth --> 1.5
529546
label --> "\$\\mathbf{u_{min}}\$"
530547
legend --> true
531548
t, fill(mpc.con.Umin[i], length(t))
@@ -537,7 +554,7 @@ end
537554
color --> 5
538555
subplot --> subplot_base + i
539556
linestyle --> :dot
540-
linewidth --> 2.0
557+
linewidth --> 1.5
541558
label --> "\$\\mathbf{u_{max}}\$"
542559
legend --> true
543560
t, fill(mpc.con.Umax[i], length(t))
@@ -559,6 +576,7 @@ end
559576
t, res.D_data[i, :]
560577
end
561578
end
579+
subplot_base += nd
562580
end
563581
# --- plant states x ---
564582
if plotx
@@ -572,19 +590,20 @@ end
572590
t, res.X_data[i, :]
573591
end
574592
end
575-
subplot_base += nx
593+
!plantIsModel && (subplot_base += nx)
576594
end
577595
# --- estimated states x̂ ---
578596
if plotx̂
579597
for i in 1:nx̂
580598
@series begin
581-
yguide --> "\$\\hat{x}_$i\$"
599+
withPlantState = plantIsModel && plotx && i nx
600+
yguide --> (withPlantState ? "\$x_$i\$" : "\$\\hat{x}_$i\$")
582601
color --> 2
583602
subplot --> subplot_base + i
584603
linestyle --> :dashdot
585604
linewidth --> 0.75
586605
label --> "\$\\mathbf{\\hat{x}}\$"
587-
legend --> false
606+
legend --> (withPlantState ? true : false)
588607
t, res.X̂_data[i, :]
589608
end
590609
end

src/predictive_control.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,11 @@ fields:
290290
```jldoctest
291291
julia> mpc = LinMPC(LinModel(tf(5, [2, 1]), 3), Nwt=[0], Hp=1, Hc=1);
292292
293-
julia> u = moveinput!(mpc, [5]);
293+
julia> u = moveinput!(mpc, [10]);
294294
295295
julia> info, sol_summary = getinfo(mpc); round.(info[:Ŷ], digits=3)
296296
1-element Vector{Float64}:
297-
5.0
297+
10.0
298298
```
299299
"""
300300
function getinfo(mpc::PredictiveController)

0 commit comments

Comments
 (0)