1+ # # ----------------- Unit tests -----------------------------------------------------------
2+ const UNIT_ESTIM = SUITE[" unit tests" ][" StateEstimator" ]
3+
4+ skf = SteadyKalmanFilter (linmodel)
5+ UNIT_ESTIM[" SteadyKalmanFilter" ][" preparestate!" ] =
6+ @benchmarkable (
7+ preparestate! ($ skf, $ y, $ d),
8+ )
9+ UNIT_ESTIM[" SteadyKalmanFilter" ][" updatestate!" ] =
10+ @benchmarkable (
11+ updatestate! ($ skf, $ u, $ y, $ d),
12+ setup= preparestate! ($ skf, $ y, $ d),
13+ )
14+ UNIT_ESTIM[" SteadyKalmanFilter" ][" evaloutput" ] =
15+ @benchmarkable (
16+ evaloutput ($ skf, $ d),
17+ setup= preparestate! ($ skf, $ y, $ d),
18+ )
19+
20+ kf = KalmanFilter (linmodel, nint_u= [1 , 1 ], direct= false )
21+ UNIT_ESTIM[" KalmanFilter" ][" preparestate!" ] =
22+ @benchmarkable (
23+ preparestate! ($ kf, $ y, $ d),
24+ )
25+ UNIT_ESTIM[" KalmanFilter" ][" updatestate!" ] =
26+ @benchmarkable (
27+ updatestate! ($ kf, $ u, $ y, $ d),
28+ setup= preparestate! ($ kf, $ y, $ d),
29+ )
30+ UNIT_ESTIM[" KalmanFilter" ][" evaloutput" ] =
31+ @benchmarkable (
32+ evaloutput ($ kf, $ d),
33+ setup= preparestate! ($ kf, $ y, $ d),
34+ )
35+
36+ lo = Luenberger (linmodel, nint_u= [1 , 1 ])
37+ UNIT_ESTIM[" Luenberger" ][" preparestate!" ] =
38+ @benchmarkable (
39+ preparestate! ($ lo, $ y, $ d),
40+ )
41+ UNIT_ESTIM[" Luenberger" ][" updatestate!" ] =
42+ @benchmarkable (
43+ updatestate! ($ lo, $ u, $ y, $ d),
44+ setup= preparestate! ($ lo, $ y, $ d),
45+ )
46+ UNIT_ESTIM[" Luenberger" ][" evaloutput" ] =
47+ @benchmarkable (
48+ evaloutput ($ lo, $ d),
49+ setup= preparestate! ($ lo, $ y, $ d),
50+ )
51+
52+ im_lin = InternalModel (linmodel)
53+ im_nonlin = InternalModel (nonlinmodel)
54+ UNIT_ESTIM[" InternalModel" ][" preparestate!" ][" LinModel" ] =
55+ @benchmarkable (
56+ preparestate! ($ im_lin, $ y, $ d),
57+ )
58+ UNIT_ESTIM[" InternalModel" ][" updatestate!" ][" LinModel" ] =
59+ @benchmarkable (
60+ updatestate! ($ im_lin, $ u, $ y, $ d),
61+ setup= preparestate! ($ im_lin, $ y, $ d),
62+ )
63+ UNIT_ESTIM[" InternalModel" ][" evaloutput" ][" LinModel" ] =
64+ @benchmarkable (
65+ evaloutput ($ im_lin, $ d),
66+ setup= preparestate! ($ im_lin, $ y, $ d),
67+ )
68+ UNIT_ESTIM[" InternalModel" ][" preparestate!" ][" NonLinModel" ] =
69+ @benchmarkable (
70+ preparestate! ($ im_nonlin, $ y, $ d),
71+ )
72+ UNIT_ESTIM[" InternalModel" ][" updatestate!" ][" NonLinModel" ] =
73+ @benchmarkable (
74+ updatestate! ($ im_nonlin, $ u, $ y, $ d),
75+ setup= preparestate! ($ im_nonlin, $ y, $ d),
76+ )
77+ UNIT_ESTIM[" InternalModel" ][" evaloutput" ][" NonLinModel" ] =
78+ @benchmarkable (
79+ evaloutput ($ im_nonlin, $ d),
80+ setup= preparestate! ($ im_nonlin, $ y, $ d),
81+ )
82+
83+ ukf_lin = UnscentedKalmanFilter (linmodel)
84+ ukf_nonlin = UnscentedKalmanFilter (nonlinmodel)
85+ UNIT_ESTIM[" UnscentedKalmanFilter" ][" preparestate!" ][" LinModel" ] =
86+ @benchmarkable (
87+ preparestate! ($ ukf_lin, $ y, $ d),
88+ )
89+ UNIT_ESTIM[" UnscentedKalmanFilter" ][" updatestate!" ][" LinModel" ] =
90+ @benchmarkable (
91+ updatestate! ($ ukf_lin, $ u, $ y, $ d),
92+ setup= preparestate! ($ ukf_lin, $ y, $ d),
93+ )
94+ UNIT_ESTIM[" UnscentedKalmanFilter" ][" evaloutput" ][" LinModel" ] =
95+ @benchmarkable (
96+ evaloutput ($ ukf_lin, $ d),
97+ setup= preparestate! ($ ukf_lin, $ y, $ d),
98+ )
99+ UNIT_ESTIM[" UnscentedKalmanFilter" ][" preparestate!" ][" NonLinModel" ] =
100+ @benchmarkable (
101+ preparestate! ($ ukf_nonlin, $ y, $ d),
102+ )
103+ UNIT_ESTIM[" UnscentedKalmanFilter" ][" updatestate!" ][" NonLinModel" ] =
104+ @benchmarkable (
105+ updatestate! ($ ukf_nonlin, $ u, $ y, $ d),
106+ setup= preparestate! ($ ukf_nonlin, $ y, $ d),
107+ )
108+ UNIT_ESTIM[" UnscentedKalmanFilter" ][" evaloutput" ][" NonLinModel" ] =
109+ @benchmarkable (
110+ evaloutput ($ ukf_nonlin, $ d),
111+ setup= preparestate! ($ ukf_nonlin, $ y, $ d),
112+ )
113+
114+ ekf_lin = ExtendedKalmanFilter (linmodel, nint_u= [1 , 1 ], direct= false )
115+ ekf_nonlin = ExtendedKalmanFilter (nonlinmodel, nint_u= [1 , 1 ], direct= false )
116+ UNIT_ESTIM[" ExtendedKalmanFilter" ][" preparestate!" ][" LinModel" ] =
117+ @benchmarkable (
118+ preparestate! ($ ekf_lin, $ y, $ d),
119+ )
120+ UNIT_ESTIM[" ExtendedKalmanFilter" ][" updatestate!" ][" LinModel" ] =
121+ @benchmarkable (
122+ updatestate! ($ ekf_lin, $ u, $ y, $ d),
123+ setup= preparestate! ($ ekf_lin, $ y, $ d),
124+ )
125+ UNIT_ESTIM[" ExtendedKalmanFilter" ][" evaloutput" ][" LinModel" ] =
126+ @benchmarkable (
127+ evaloutput ($ ekf_lin, $ d),
128+ setup= preparestate! ($ ekf_lin, $ y, $ d),
129+ )
130+ UNIT_ESTIM[" ExtendedKalmanFilter" ][" preparestate!" ][" NonLinModel" ] =
131+ @benchmarkable (
132+ preparestate! ($ ekf_nonlin, $ y, $ d),
133+ )
134+ UNIT_ESTIM[" ExtendedKalmanFilter" ][" updatestate!" ][" NonLinModel" ] =
135+ @benchmarkable (
136+ updatestate! ($ ekf_nonlin, $ u, $ y, $ d),
137+ setup= preparestate! ($ ekf_nonlin, $ y, $ d),
138+ )
139+ UNIT_ESTIM[" ExtendedKalmanFilter" ][" evaloutput" ][" NonLinModel" ] =
140+ @benchmarkable (
141+ evaloutput ($ ekf_nonlin, $ d),
142+ setup= preparestate! ($ ekf_nonlin, $ y, $ d),
143+ )
144+
145+ mhe_lin_curr = MovingHorizonEstimator (linmodel, He= 10 , direct= true )
146+ mhe_lin_pred = MovingHorizonEstimator (linmodel, He= 10 , direct= false )
147+ mhe_nonlin_curr = MovingHorizonEstimator (nonlinmodel, He= 10 , direct= true )
148+ mhe_nonlin_pred = MovingHorizonEstimator (nonlinmodel, He= 10 , direct= false )
149+
150+ samples, evals, seconds = 5000 , 1 , 60
151+ UNIT_ESTIM[" MovingHorizonEstimator" ][" preparestate!" ][" LinModel" ][" Current form" ] =
152+ @benchmarkable (
153+ preparestate! ($ mhe_lin_curr, $ y, $ d),
154+ samples= samples, evals= evals, seconds= seconds,
155+ )
156+ UNIT_ESTIM[" MovingHorizonEstimator" ][" updatestate!" ][" LinModel" ][" Current form" ] =
157+ @benchmarkable (
158+ updatestate! ($ mhe_lin_curr, $ u, $ y, $ d),
159+ setup= preparestate! ($ mhe_lin_curr, $ y, $ d),
160+ samples= samples, evals= evals, seconds= seconds,
161+ )
162+ UNIT_ESTIM[" MovingHorizonEstimator" ][" preparestate!" ][" LinModel" ][" Prediction form" ] =
163+ @benchmarkable (
164+ preparestate! ($ mhe_lin_pred, $ y, $ d),
165+ samples= samples, evals= evals, seconds= seconds,
166+ )
167+ UNIT_ESTIM[" MovingHorizonEstimator" ][" updatestate!" ][" LinModel" ][" Prediction form" ] =
168+ @benchmarkable (
169+ updatestate! ($ mhe_lin_pred, $ u, $ y, $ d),
170+ setup= preparestate! ($ mhe_lin_pred, $ y, $ d),
171+ samples= samples, evals= evals, seconds= seconds,
172+ )
173+ UNIT_ESTIM[" MovingHorizonEstimator" ][" preparestate!" ][" NonLinModel" ][" Current form" ] =
174+ @benchmarkable (
175+ preparestate! ($ mhe_nonlin_curr, $ y, $ d),
176+ samples= samples, evals= evals, seconds= seconds,
177+ )
178+ UNIT_ESTIM[" MovingHorizonEstimator" ][" updatestate!" ][" NonLinModel" ][" Current form" ] =
179+ @benchmarkable (
180+ updatestate! ($ mhe_nonlin_curr, $ u, $ y, $ d),
181+ setup= preparestate! ($ mhe_nonlin_curr, $ y, $ d),
182+ samples= samples, evals= evals, seconds= seconds,
183+ )
184+ UNIT_ESTIM[" MovingHorizonEstimator" ][" preparestate!" ][" NonLinModel" ][" Prediction form" ] =
185+ @benchmarkable (
186+ preparestate! ($ mhe_nonlin_pred, $ y, $ d),
187+ samples= samples, evals= evals, seconds= seconds,
188+ )
189+ UNIT_ESTIM[" MovingHorizonEstimator" ][" updatestate!" ][" NonLinModel" ][" Prediction form" ] =
190+ @benchmarkable (
191+ updatestate! ($ mhe_nonlin_pred, $ u, $ y, $ d),
192+ setup= preparestate! ($ mhe_nonlin_pred, $ y, $ d),
193+ samples= samples, evals= evals, seconds= seconds,
194+ )
195+
196+ # # ----------------- Case studies ---------------------------------------------------
197+ const CASE_ESTIM = SUITE[" case studies" ][" StateEstimator" ]
198+
199+ # # ----------------- Case study: CSTR -----------------------------------------------------
200+ G = [ tf (1.90 , [18 , 1 ]) tf (1.90 , [18 , 1 ]);
201+ tf (- 0.74 ,[8 , 1 ]) tf (0.74 , [8 , 1 ]) ]
202+ uop, yop = [20 , 20 ], [50 , 30 ]
203+ model = setop! (LinModel (G, 2.0 ); uop, yop)
204+ plant = setop! (LinModel (G, 2.0 ); uop, yop)
205+ plant. A[diagind (plant. A)] .- = 0.1 # plant-model mismatch
206+ function test_mhe (mhe, plant)
207+ plant. x0 .= 0 ; y = plant ()
208+ initstate! (mhe, plant. uop, y)
209+ N = 75 ; u = [20 , 20 ]; ul = 0
210+ U, Y, Ŷ = zeros (2 , N), zeros (2 , N), zeros (2 , N)
211+ for i = 1 : N
212+ i == 26 && (u = [15 , 25 ])
213+ i == 51 && (ul = - 10 )
214+ y = plant ()
215+ preparestate! (mhe, y)
216+ ŷ = evaloutput (mhe)
217+ U[:,i], Y[:,i], Ŷ[:,i] = u, y, ŷ
218+ updatestate! (mhe, u, y)
219+ updatestate! (plant, u+ [0 ,ul])
220+ end
221+ return U, Y, Ŷ
222+ end
223+ He = 10 ; nint_u = [1 , 1 ]; σQint_u = [1 , 2 ]
224+
225+ optim = JuMP. Model (OSQP. Optimizer, add_bridges= false )
226+ direct = true
227+ mhe_cstr_osqp_curr = MovingHorizonEstimator (model; He, nint_u, σQint_u, optim, direct)
228+ mhe_cstr_osqp_curr = setconstraint! (mhe_cstr_osqp_curr, v̂min= [- 1 , - 0.5 ], v̂max= [+ 1 , + 0.5 ])
229+ JuMP. unset_time_limit_sec (mhe_cstr_osqp_curr. optim)
230+
231+ optim = JuMP. Model (OSQP. Optimizer, add_bridges= false )
232+ direct = false
233+ mhe_cstr_osqp_pred = MovingHorizonEstimator (model; He, nint_u, σQint_u, optim, direct)
234+ mhe_cstr_osqp_pred = setconstraint! (mhe_cstr_osqp_pred, v̂min= [- 1 , - 0.5 ], v̂max= [+ 1 , + 0.5 ])
235+ JuMP. unset_time_limit_sec (mhe_cstr_osqp_pred. optim)
236+
237+ optim = JuMP. Model (DAQP. Optimizer, add_bridges= false )
238+ direct = true
239+ mhe_cstr_daqp_curr = MovingHorizonEstimator (model; He, nint_u, σQint_u, optim, direct)
240+ mhe_cstr_daqp_curr = setconstraint! (mhe_cstr_daqp_curr, v̂min= [- 1 , - 0.5 ], v̂max= [+ 1 , + 0.5 ])
241+ JuMP. set_attribute (mhe_cstr_daqp_curr. optim, " eps_prox" , 1e-6 ) # needed to support hessians H≥0
242+
243+ optim = JuMP. Model (DAQP. Optimizer, add_bridges= false )
244+ direct = false
245+ mhe_cstr_daqp_pred = MovingHorizonEstimator (model; He, nint_u, σQint_u, optim, direct)
246+ mhe_cstr_daqp_pred = setconstraint! (mhe_cstr_daqp_pred, v̂min= [- 1 , - 0.5 ], v̂max= [+ 1 , + 0.5 ])
247+ JuMP. set_attribute (mhe_cstr_daqp_pred. optim, " eps_prox" , 1e-6 ) # needed to support hessians H≥0
248+
249+ optim = JuMP. Model (optimizer_with_attributes (Ipopt. Optimizer," sb" => " yes" ), add_bridges= false )
250+ direct = true
251+ mhe_cstr_ipopt_curr = MovingHorizonEstimator (model; He, nint_u, σQint_u, optim, direct)
252+ mhe_cstr_ipopt_curr = setconstraint! (mhe_cstr_ipopt_curr, v̂min= [- 1 , - 0.5 ], v̂max= [+ 1 , + 0.5 ])
253+ JuMP. unset_time_limit_sec (mhe_cstr_ipopt_curr. optim)
254+
255+ optim = JuMP. Model (optimizer_with_attributes (Ipopt. Optimizer," sb" => " yes" ), add_bridges= false )
256+ direct = false
257+ mhe_cstr_ipopt_pred = MovingHorizonEstimator (model; He, nint_u, σQint_u, optim, direct)
258+ mhe_cstr_ipopt_pred = setconstraint! (mhe_cstr_ipopt_pred, v̂min= [- 1 , - 0.5 ], v̂max= [+ 1 , + 0.5 ])
259+ JuMP. unset_time_limit_sec (mhe_cstr_ipopt_pred. optim)
260+
261+ samples, evals = 500 , 1
262+ CASE_ESTIM[" CSTR" ][" MovingHorizonEstimator" ][" OSQP" ][" Current form" ] =
263+ @benchmarkable (test_mhe ($ mhe_cstr_osqp_curr, $ plant);
264+ samples= samples, evals= evals
265+ )
266+ CASE_ESTIM[" CSTR" ][" MovingHorizonEstimator" ][" OSQP" ][" Prediction form" ] =
267+ @benchmarkable (test_mhe ($ mhe_cstr_osqp_pred, $ plant);
268+ samples= samples, evals= evals
269+ )
270+ CASE_ESTIM[" CSTR" ][" MovingHorizonEstimator" ][" DAQP" ][" Current form" ] =
271+ @benchmarkable (test_mhe ($ mhe_cstr_daqp_curr, $ plant);
272+ samples= samples, evals= evals
273+ )
274+ CASE_ESTIM[" CSTR" ][" MovingHorizonEstimator" ][" DAQP" ][" Prediction form" ] =
275+ @benchmarkable (test_mhe ($ mhe_cstr_daqp_pred, $ plant);
276+ samples= samples, evals= evals
277+ )
278+ CASE_ESTIM[" CSTR" ][" MovingHorizonEstimator" ][" Ipopt" ][" Current form" ] =
279+ @benchmarkable (test_mhe ($ mhe_cstr_ipopt_curr, $ plant);
280+ samples= samples, evals= evals
281+ )
282+ CASE_ESTIM[" CSTR" ][" MovingHorizonEstimator" ][" Ipopt" ][" Prediction form" ] =
283+ @benchmarkable (test_mhe ($ mhe_cstr_ipopt_pred, $ plant);
284+ samples= samples, evals= evals
285+ )
0 commit comments