11struct SimResult{NT<: Real , O<: Union{SimModel, StateEstimator, PredictiveController} }
2- obj:: O # simulated instance
3- T_data :: Vector{NT} # time in seconds
4- Y_data :: Matrix{NT} # plant outputs (both measured and unmeasured)
5- Ry_data:: Matrix{NT} # output setpoints
6- Ŷ_data :: Matrix{NT} # estimated outputs
7- U_data :: Matrix{NT} # manipulated inputs
8- Ud_data:: Matrix{NT} # manipulated inputs including load disturbances
9- Ru_data:: Matrix{NT} # manipulated input setpoints
10- D_data :: Matrix{NT} # measured disturbances
11- X_data :: Matrix{NT} # plant states
12- X̂_data :: Matrix{NT} # estimated states
2+ obj:: O # simulated instance
3+ xname :: Vector{String} # plant state names
4+ T_data :: Vector{NT} # time in seconds
5+ Y_data :: Matrix{NT} # plant outputs (both measured and unmeasured)
6+ Ry_data:: Matrix{NT} # output setpoints
7+ Ŷ_data :: Matrix{NT} # estimated outputs
8+ U_data :: Matrix{NT} # manipulated inputs
9+ Ud_data:: Matrix{NT} # manipulated inputs including load disturbances
10+ Ru_data:: Matrix{NT} # manipulated input setpoints
11+ D_data :: Matrix{NT} # measured disturbances
12+ X_data :: Matrix{NT} # plant states
13+ X̂_data :: Matrix{NT} # estimated states
1314end
1415
1516"""
@@ -36,16 +37,17 @@ Simply call `plot` on them.
3637- `Ŷ_data=nothing` or *`Yhat_data`* : estimated outputs
3738- `Ry_data=nothing` : plant output setpoints
3839- `Ru_data=nothing` : manipulated input setpoints
40+ - `plant=get_model(obj)` : simulated plant model, default to `obj` internal plant model
3941
4042# Examples
4143```jldoctest
42- julia> plant = LinModel(tf(1, [1, 1]), 1.0); N = 5; U_data = fill(1.0, 1, N);
44+ julia> model = LinModel(tf(1, [1, 1]), 1.0); N = 5; U_data = fill(1.0, 1, N);
4345
44- julia> Y_data = reduce(hcat, (updatestate!(plant , U_data[:, i]); plant ()) for i=1:N)
46+ julia> Y_data = reduce(hcat, (updatestate!(model , U_data[:, i]); model ()) for i=1:N)
45471×5 Matrix{Float64}:
4648 0.632121 0.864665 0.950213 0.981684 0.993262
4749
48- julia> res = SimResult(plant , U_data, Y_data)
50+ julia> res = SimResult(model , U_data, Y_data)
4951Simulation results of LinModel with 5 time steps.
5052```
5153"""
@@ -60,10 +62,12 @@ function SimResult(
6062 Ry_data = nothing ,
6163 Ru_data = nothing ,
6264 X̂_data = Xhat_data,
63- Ŷ_data = Yhat_data
65+ Ŷ_data = Yhat_data,
66+ plant = get_model (obj)
6467) where {NT<: Real , O<: Union{SimModel{NT}, StateEstimator{NT}, PredictiveController{NT}} }
6568 model = get_model (obj)
66- Ts, nu, ny, nx, nx̂ = model. Ts, model. nu, model. ny, model. nx, get_nx̂ (obj)
69+ Ts, nu, ny, nx̂ = model. Ts, model. nu, model. ny, get_nx̂ (obj)
70+ nx = plant. nx
6771 N = size (U_data, 2 )
6872 T_data = collect (Ts* (0 : N- 1 ))
6973 isnothing (X_data) && (X_data = fill (NaN , nx, N))
@@ -72,13 +76,16 @@ function SimResult(
7276 isnothing (Ru_data) && (Ru_data = fill (NaN , nu, N))
7377 isnothing (Ŷ_data) && (Ŷ_data = fill (NaN , ny, N))
7478 NU, NY, NX, NX̂ = size (U_data, 2 ), size (Y_data, 2 ), size (X_data, 2 ), size (X̂_data, 2 )
75- NRy, NRu = size (Ry_data, 2 ), size (Ru_data, 2 )
76- if ! (NU == NY == NX == NX̂ == NRy == NRu)
79+ NRy, NRu, NŶ = size (Ry_data, 2 ), size (Ru_data, 2 ), size (Ŷ_data , 2 )
80+ if ! (NU == NY == NX == NX̂ == NRy == NRu == NŶ )
7781 throw (ArgumentError (" All arguments must have the same number of columns (time steps)" ))
7882 end
7983 size (Y_data, 2 ) == N || error (" Y_data must be of size ($ny , $N )" )
80- return SimResult {NT, O} (obj, T_data, Y_data, Ry_data, Ŷ_data, U_data, U_data,
81- Ru_data, D_data, X_data, X̂_data)
84+ return SimResult {NT, O} (
85+ obj, plant. xname,
86+ T_data, Y_data, Ry_data, Ŷ_data,
87+ U_data, U_data, Ru_data, D_data, X_data, X̂_data
88+ )
8289end
8390
8491get_model (model:: SimModel ) = model
@@ -136,8 +143,11 @@ function sim!(
136143 X_data[:, i] .= plant. x0 .+ plant. xop
137144 updatestate! (plant, u, d)
138145 end
139- return SimResult (plant, T_data, Y_data, U_data, Y_data,
140- U_data, U_data, U_data, D_data, X_data, X_data)
146+ return SimResult (
147+ plant, plant. xname,
148+ T_data, Y_data, U_data, Y_data,
149+ U_data, U_data, U_data, D_data, X_data, X_data
150+ )
141151end
142152
143153@doc raw """
@@ -289,8 +299,11 @@ function sim_closedloop!(
289299 x[:] += x_noise.* randn (plant. nx)
290300 updatestate! (est_mpc, u, ym, d)
291301 end
292- res = SimResult (est_mpc, T_data, Y_data, U_Ry_data, Ŷ_data,
293- U_data, Ud_data, Ru_data, D_data, X_data, X̂_data)
302+ res = SimResult (
303+ est_mpc, plant. xname,
304+ T_data, Y_data, U_Ry_data, Ŷ_data,
305+ U_data, Ud_data, Ru_data, D_data, X_data, X̂_data
306+ )
294307 plant. x0 .= old_x0
295308 return res
296309end
@@ -319,6 +332,13 @@ Plot the simulation results of a [`SimModel`](@ref).
319332- `plotu=true` : plot manipulated inputs ``\m athbf{u}``
320333- `plotd=true` : plot measured disturbances ``\m athbf{d}`` if applicable
321334- `plotx=false` : plot plant states ``\m athbf{x}``
335+
336+ # Examples
337+ ```julia-repl
338+ julia> res = sim!(LinModel(tf(2, [10, 1]), 2.0), 25);
339+
340+ julia> plot(res, plotu=false);
341+ ```
322342"""
323343plot (:: Nothing , :: SimResult{<:Real, <:SimModel} )
324344
@@ -337,7 +357,7 @@ plot(::Nothing, ::SimResult{<:Real, <:SimModel})
337357 uname = model. uname
338358 yname = model. yname
339359 dname = model. dname
340- xname = model . xname
360+ xname = res . xname
341361 layout_mat = [(ny, 1 )]
342362 plotu && (layout_mat = [layout_mat (nu, 1 )])
343363 (plotd && nd ≠ 0 ) && (layout_mat = [layout_mat (nd, 1 )])
@@ -424,6 +444,13 @@ Plot the simulation results of a [`StateEstimator`](@ref).
424444- `plotx̂max=true` or *`plotxhatmax`* : plot estimated state upper bounds ``\m athbf{x̂_{max}}``
425445 if applicable
426446- `<keyword arguments>` of [`plot(::SimResult{<:Real, <:SimModel})`](@ref)
447+
448+ # Examples
449+ ```julia-repl
450+ julia> res = sim!(KalmanFilter(LinModel(tf(3, [2.0, 1]), 1.0)), 25, [0], y_step=[1]);
451+
452+ julia> plot(res, plotu=false, plotŷ=true, plotxwithx̂=true);
453+ ```
427454"""
428455plot (:: Nothing , :: SimResult{<:Real, <:StateEstimator} )
429456
@@ -454,7 +481,8 @@ plot(::Nothing, ::SimResult{<:Real, <:StateEstimator})
454481 uname = model. uname
455482 yname = model. yname
456483 dname = model. dname
457- xname = model. xname
484+ x̂name = [model. xname; [" \$ x_{$i }\$ " for i in (nx+ 1 ): (nx̂)]]
485+ xname = res. xname
458486 layout_mat = [(ny, 1 )]
459487 plotu && (layout_mat = [layout_mat (nu, 1 )])
460488 (plotd && nd ≠ 0 ) && (layout_mat = [layout_mat (nd, 1 )])
@@ -541,7 +569,7 @@ plot(::Nothing, ::SimResult{<:Real, <:StateEstimator})
541569 withPlantState = plotxwithx̂ && i ≤ nx
542570 @series begin
543571 i == nx̂ && (xguide --> " Time (s)" )
544- yguide --> (withPlantState ? xname[i] : " \$\\ hat{x}_{ $i } \$ " )
572+ yguide --> (withPlantState ? xname[i] : x̂name[i] )
545573 color --> 2
546574 subplot --> subplot_base + i
547575 linestyle --> :dashdot
@@ -553,7 +581,7 @@ plot(::Nothing, ::SimResult{<:Real, <:StateEstimator})
553581 if plotx̂min && ! isinf (X̂min[end - 2 * nx̂+ i])
554582 @series begin
555583 i == nx̂ && (xguide --> " Time (s)" )
556- yguide --> (withPlantState ? xname[i] : " \$\\ hat{x}_{ $i } \$ " )
584+ yguide --> (withPlantState ? xname[i] : x̂name[i] )
557585 color --> 3
558586 subplot --> subplot_base + i
559587 linestyle --> :dot
@@ -566,7 +594,7 @@ plot(::Nothing, ::SimResult{<:Real, <:StateEstimator})
566594 if plotx̂max && ! isinf (X̂max[end - 2 * nx̂+ i])
567595 @series begin
568596 i == nx̂ && (xguide --> " Time (s)" )
569- yguide --> (withPlantState ? xname[i] : " \$\\ hat{x}_{ $i } \$ " )
597+ yguide --> (withPlantState ? xname[i] : x̂name[i] )
570598 color --> 4
571599 subplot --> subplot_base + i
572600 linestyle --> :dot
@@ -599,6 +627,15 @@ Plot the simulation results of a [`PredictiveController`](@ref).
599627- `<keyword arguments>` of [`plot(::SimResult{<:Real, <:SimModel})`](@ref)
600628- `<keyword arguments>` of [`plot(::SimResult{<:Real, <:StateEstimator})`](@ref)
601629
630+ # Examples
631+ ```julia-repl
632+ julia> model = LinModel(tf(2, [5.0, 1]), 1.0);
633+
634+ julia> res = sim!(setconstraint!(LinMPC(model), umax=[1.0]), 30, [0], u_step=[-1]);
635+
636+ julia> plot(res, plotŷ=true, plotry=true, plotumax=true);
637+ ```
638+
602639"""
603640plot (:: Nothing , :: SimResult{<:Real, <:PredictiveController} )
604641
@@ -635,7 +672,8 @@ plot(::Nothing, ::SimResult{<:Real, <:PredictiveController})
635672 uname = model. uname
636673 yname = model. yname
637674 dname = model. dname
638- xname = model. xname
675+ x̂name = [model. xname; [" \$ x_{$i }\$ " for i in (nx+ 1 ): (nx̂)]]
676+ xname = res. xname
639677 layout_mat = [(ny, 1 )]
640678 plotu && (layout_mat = [layout_mat (nu, 1 )])
641679 (plotd && nd ≠ 0 ) && (layout_mat = [layout_mat (nd, 1 )])
@@ -803,7 +841,7 @@ plot(::Nothing, ::SimResult{<:Real, <:PredictiveController})
803841 withPlantState = plotxwithx̂ && i ≤ nx
804842 @series begin
805843 i == nx̂ && (xguide --> " Time (s)" )
806- yguide --> (withPlantState ? xname[i] : " \$\\ hat{x}_{ $i } \$ " )
844+ yguide --> (withPlantState ? xname[i] : x̂name[i] )
807845 color --> 2
808846 subplot --> subplot_base + i
809847 linestyle --> :dashdot
@@ -815,7 +853,7 @@ plot(::Nothing, ::SimResult{<:Real, <:PredictiveController})
815853 if plotx̂min && ! isinf (X̂min[end - 2 * nx̂+ i])
816854 @series begin
817855 i == nx̂ && (xguide --> " Time (s)" )
818- yguide --> (withPlantState ? xname[i] : " \$\\ hat{x}_{ $i } \$ " )
856+ yguide --> (withPlantState ? xname[i] : x̂name[i] )
819857 color --> 3
820858 subplot --> subplot_base + i
821859 linestyle --> :dot
@@ -828,7 +866,7 @@ plot(::Nothing, ::SimResult{<:Real, <:PredictiveController})
828866 if plotx̂max && ! isinf (X̂max[end - 2 * nx̂+ i])
829867 @series begin
830868 i == nx̂ && (xguide --> " Time (s)" )
831- yguide --> (withPlantState ? xname[i] : " \$\\ hat{x}_{ $i } \$ " )
869+ yguide --> (withPlantState ? xname[i] : x̂name[i] )
832870 color --> 4
833871 subplot --> subplot_base + i
834872 linestyle --> :dot
0 commit comments