Skip to content

Commit adf78e0

Browse files
committed
bench: added some NonLinMPC benchmarks on pendulum
1 parent 9774a36 commit adf78e0

File tree

5 files changed

+122
-34
lines changed

5 files changed

+122
-34
lines changed

benchmark/0_bench_setup.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
Ts = 400.0
22
sys = [ tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]);
33
tf(-0.74,[800.0,1]) tf(0.74,[800.0,1]) tf(-0.74,[800.0,1]) ]
4-
function f!(ẋ, x, u, d, p)
4+
function f_lin!(ẋ, x, u, d, p)
55
mul!(ẋ, p.A, x)
66
mul!(ẋ, p.Bu, u, 1, 1)
77
mul!(ẋ, p.Bd, d, 1, 1)
88
return nothing
99
end
10-
function h!(y, x, d, p)
10+
function h_lin!(y, x, d, p)
1111
mul!(y, p.C, x)
1212
mul!(y, p.Dd, d, 1, 1)
1313
return nothing
14-
end
14+
end
15+
linmodel = setop!(LinModel(sys, Ts, i_d=[3]), uop=[10, 50], yop=[50, 30], dop=[5])
16+
nonlinmodel = NonLinModel(f_lin!, h_lin!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing)
17+
nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5])
18+
u, d, y = [10, 50], [5], [50, 30]

benchmark/1_bench_sim_model.jl

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
1-
linmodel = setop!(LinModel(sys, Ts, i_d=[3]), uop=[10, 50], yop=[50, 30], dop=[5])
2-
nonlinmodel = NonLinModel(f!, h!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing)
3-
nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5])
4-
u, d, y = [10, 50], [5], [50, 30]
5-
61
## ----------------- Runtime benchmarks ---------------------------------------------
72
# TODO: Add runtime benchmarks for SimModel
83

94

105
## ----------------- Allocation benchmarks ------------------------------------------
116
samples, evals = 1, 1
12-
SUITE["allocation"]["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable(
7+
ALLOC["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable(
138
updatestate!($linmodel, $u, $d); samples=samples, evals=evals
149
)
15-
SUITE["allocation"]["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable(
10+
ALLOC["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable(
1611
evaloutput($linmodel, $d); samples=samples, evals=evals
1712
)
18-
SUITE["allocation"]["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable(
13+
ALLOC["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable(
1914
updatestate!($nonlinmodel, $u, $d); samples=samples, evals=evals
2015
)
21-
SUITE["allocation"]["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable(
16+
ALLOC["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable(
2217
evaloutput($nonlinmodel, $d); samples=samples, evals=evals
2318
)
24-
SUITE["allocation"]["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable(
19+
ALLOC["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable(
2520
linearize!($linmodel, $nonlinmodel); samples=samples, evals=evals
2621
)

benchmark/2_bench_state_estim.jl

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,89 +6,89 @@
66
samples, evals = 1, 1
77

88
skf = SteadyKalmanFilter(linmodel)
9-
SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] =
9+
ALLOC["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] =
1010
@benchmarkable(
1111
preparestate!($skf, $y, $d),
1212
samples=samples, evals=evals
1313
)
14-
SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] =
14+
ALLOC["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] =
1515
@benchmarkable(
1616
updatestate!($skf, $u, $y, $d),
1717
setup=preparestate!($skf, $y, $d),
1818
samples=samples, evals=evals
1919
)
20-
SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] =
20+
ALLOC["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] =
2121
@benchmarkable(
2222
evaloutput($skf, $d),
2323
setup=preparestate!($skf, $y, $d),
2424
samples=samples, evals=evals
2525
)
2626

2727
kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false)
28-
SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["preparestate!"] =
28+
ALLOC["StateEstimator"]["KalmanFilter"]["preparestate!"] =
2929
@benchmarkable(
3030
preparestate!($kf, $y, $d),
3131
samples=samples, evals=evals
3232
)
33-
SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["updatestate!"] =
33+
ALLOC["StateEstimator"]["KalmanFilter"]["updatestate!"] =
3434
@benchmarkable(
3535
updatestate!($kf, $u, $y, $d),
3636
setup=preparestate!($kf, $y, $d),
3737
samples=samples, evals=evals
3838
)
3939

4040
lo = Luenberger(linmodel, nint_u=[1, 1])
41-
SUITE["allocation"]["StateEstimator"]["Luenberger"]["preparestate!"] =
41+
ALLOC["StateEstimator"]["Luenberger"]["preparestate!"] =
4242
@benchmarkable(
4343
preparestate!($lo, $y, $d),
4444
samples=samples, evals=evals
4545
)
46-
SUITE["allocation"]["StateEstimator"]["Luenberger"]["updatestate!"] =
46+
ALLOC["StateEstimator"]["Luenberger"]["updatestate!"] =
4747
@benchmarkable(
4848
updatestate!($lo, $u, $y, $d),
4949
setup=preparestate!($lo, $y, $d),
5050
samples=samples, evals=evals
5151
)
5252

5353
im = InternalModel(nonlinmodel)
54-
SUITE["allocation"]["StateEstimator"]["InternalModel"]["preparestate!"] =
54+
ALLOC["StateEstimator"]["InternalModel"]["preparestate!"] =
5555
@benchmarkable(
5656
preparestate!($im, $y, $d),
5757
samples=samples, evals=evals
5858
)
59-
SUITE["allocation"]["StateEstimator"]["InternalModel"]["updatestate!"] =
59+
ALLOC["StateEstimator"]["InternalModel"]["updatestate!"] =
6060
@benchmarkable(
6161
updatestate!($im, $u, $y, $d),
6262
setup=preparestate!($im, $y, $d),
6363
samples=samples, evals=evals
6464
)
6565

6666
ukf = UnscentedKalmanFilter(nonlinmodel)
67-
SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] =
67+
ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] =
6868
@benchmarkable(
6969
preparestate!($ukf, $y, $d),
7070
samples=samples, evals=evals
7171
)
72-
SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] =
72+
ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] =
7373
@benchmarkable(
7474
updatestate!($ukf, $u, $y, $d),
7575
setup=preparestate!($ukf, $y, $d),
7676
samples=samples, evals=evals
7777
)
78-
SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] =
78+
ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] =
7979
@benchmarkable(
8080
evaloutput($ukf, $d),
8181
setup=preparestate!($ukf, $y, $d),
8282
samples=samples, evals=evals
8383
)
8484

8585
ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false)
86-
SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] =
86+
ALLOC["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] =
8787
@benchmarkable(
8888
preparestate!($ekf, $y, $d),
8989
samples=samples, evals=evals
9090
)
91-
SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] =
91+
ALLOC["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] =
9292
@benchmarkable(
9393
updatestate!($ekf, $u, $y, $d),
9494
setup=preparestate!($ekf, $y, $d),

benchmark/3_bench_predictive_control.jl

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
## ----------------- Runtime benchmarks : CSTR ----------------------------------------
12
G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]);
23
tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ]
34
uop, yop = [20, 20], [50, 30]
@@ -20,7 +21,6 @@ function test_mpc(mpc, plant)
2021
return U, Y, Ry
2122
end
2223

23-
## ----------------- Runtime benchmarks ---------------------------------------------
2424
optim = JuMP.Model(OSQP.Optimizer, add_bridges=false)
2525
transcription = SingleShooting()
2626
mpc_osqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf])
@@ -38,33 +38,119 @@ mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf
3838
optim = JuMP.Model(DAQP.Optimizer, add_bridges=false)
3939
transcription = MultipleShooting()
4040
mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf])
41-
# needed to solve Hessians with eigenvalues at zero, like in MultipleShooting transcription:
41+
# needed to solve Hessians with eigenvalues at zero, like with MultipleShooting:
4242
JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6)
4343

44+
optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false)
45+
transcription = SingleShooting()
46+
mpc_ipopt_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf])
47+
JuMP.unset_time_limit_sec(mpc_ipopt_ss.optim)
48+
49+
optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false)
50+
transcription = MultipleShooting()
51+
mpc_ipopt_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf])
52+
JuMP.unset_time_limit_sec(mpc_ipopt_ms.optim)
53+
4454
samples, evals = 500, 1
45-
SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] =
55+
RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] =
4656
@benchmarkable(test_mpc($mpc_osqp_ss, $model);
4757
samples=samples, evals=evals
4858
)
49-
SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] =
59+
RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] =
5060
@benchmarkable(test_mpc($mpc_osqp_ms, $model);
5161
samples=samples, evals=evals
5262
)
53-
SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] =
63+
RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] =
5464
@benchmarkable(test_mpc($mpc_daqp_ss, $model);
5565
samples=samples, evals=evals
5666
)
57-
SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] =
67+
RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] =
5868
@benchmarkable(test_mpc($mpc_daqp_ms, $model);
5969
samples=samples, evals=evals
6070
)
71+
RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["Ipopt"]["SingleShooting"] =
72+
@benchmarkable(test_mpc($mpc_ipopt_ss, $model);
73+
samples=samples, evals=evals
74+
)
75+
RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["Ipopt"]["MultipleShooting"] =
76+
@benchmarkable(test_mpc($mpc_ipopt_ms, $model);
77+
samples=samples, evals=evals
78+
)
79+
80+
# ----------------- Runtime benchmarks : Pendulum ---------------------------------------
81+
function f!(ẋ, x, u, _ , p)
82+
g, L, K, m = p # [m/s²], [m], [kg/s], [kg]
83+
θ, ω = x[1], x[2] # [rad], [rad/s]
84+
τ = u[1] # [Nm]
85+
ẋ[1] = ω
86+
ẋ[2] = -g/L*sin(θ) - K/m*ω + τ/m/L^2
87+
end
88+
h!(y, x, _ , _ ) = (y[1] = 180/π*x[1]) # [°]
89+
p = [9.8, 0.4, 1.2, 0.3]
90+
nu = 1; nx = 2; ny = 1; Ts = 0.1
91+
model = NonLinModel(f!, h!, Ts, nu, nx, ny; p)
92+
σQ = [0.1, 1.0]; σR=[5.0]; nint_u=[1]; σQint_u=[0.1]
93+
estim = UnscentedKalmanFilter(model; σQ, σR, nint_u, σQint_u)
94+
p_plant = copy(p); p_plant[3] = 1.25*p[3]
95+
plant = NonLinModel(f!, h!, Ts, nu, nx, ny; p=p_plant)
96+
N = 35; u = [0.5];
97+
98+
Hp, Hc, Mwt, Nwt, Cwt = 20, 2, [0.5], [2.5], Inf
99+
umin, umax = [-1.5], [+1.5]
100+
x_0 = [0, 0]; x̂_0 = [0, 0, 0]; ry = [180]
101+
102+
optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false)
103+
transcription = SingleShooting()
104+
nmpc_ipopt_ss = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription)
105+
nmpc_ipopt_ss = setconstraint!(nmpc_ipopt_ss; umin, umax)
106+
JuMP.unset_time_limit_sec(nmpc_ipopt_ss.optim)
61107

108+
optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false)
109+
transcription = MultipleShooting()
110+
nmpc_ipopt_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription)
111+
nmpc_ipopt_ms = setconstraint!(nmpc_ipopt_ms; umin, umax)
112+
JuMP.unset_time_limit_sec(nmpc_ipopt_ms.optim)
113+
114+
optim = JuMP.Model(MadNLP.Optimizer, add_bridges=false)
115+
transcription = SingleShooting()
116+
nmpc_madnlp_ss = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription)
117+
nmpc_madnlp_ss = setconstraint!(nmpc_madnlp_ss; umin, umax)
118+
JuMP.unset_time_limit_sec(nmpc_madnlp_ss.optim)
119+
120+
optim = JuMP.Model(MadNLP.Optimizer, add_bridges=false)
121+
transcription = MultipleShooting()
122+
nmpc_madnlp_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription)
123+
nmpc_madnlp_ms = setconstraint!(nmpc_madnlp_ms; umin, umax)
124+
JuMP.unset_time_limit_sec(nmpc_madnlp_ms.optim)
125+
126+
samples, evals, seconds = 50, 1, 15*60
127+
RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["SingleShooting"] =
128+
@benchmarkable(
129+
sim!($nmpc_ipopt_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0),
130+
samples=samples, evals=evals, seconds=seconds
131+
)
132+
RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["MultipleShooting"] =
133+
@benchmarkable(
134+
sim!($nmpc_ipopt_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0),
135+
samples=samples, evals=evals, seconds=seconds
136+
)
137+
RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["SingleShooting"] =
138+
@benchmarkable(
139+
sim!($nmpc_madnlp_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0),
140+
samples=samples, evals=evals, seconds=seconds
141+
)
142+
# TODO: does not work with MadNLP and MultipleShooting, figure out why
143+
# RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["MultipleShooting"] =
144+
# @benchmarkable(
145+
# sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0),
146+
# samples=samples, evals=evals, seconds=seconds
147+
# )
62148

63149
# ---------------------- Allocation benchmarks ------------------------------------------
64150
empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1])
65151

66152
samples, evals = 1, 1
67-
SUITE["allocation"]["PredictiveController"]["ExplicitMPC"]["moveinput!"] =
153+
ALLOC["PredictiveController"]["ExplicitMPC"]["moveinput!"] =
68154
@benchmarkable(
69155
moveinput!($empc, $y, $d),
70156
setup=preparestate!($empc, $y, $d),

benchmark/benchmarks.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ using JuMP, OSQP, DAQP, Ipopt, MadNLP
44

55
const SUITE = BenchmarkGroup(["ModelPredictiveControl"])
66

7+
const ALLOC = SUITE["allocation"] = BenchmarkGroup(["allocation-free","no-allocation"])
8+
const RUNTIME = SUITE["runtime"] = BenchmarkGroup(["performance","speed"])
9+
710
include("0_bench_setup.jl")
811
include("1_bench_sim_model.jl")
912
include("2_bench_state_estim.jl")

0 commit comments

Comments
 (0)