Skip to content

Commit c8694f2

Browse files
committed
Add autotune_nomad.jl
1 parent bbcb521 commit c8694f2

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
88
KiteUtils = "90980105-b163-44e5-ba9f-8b1c83bb0533"
99
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1010
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
11+
NOMAD = "02130f1c-4665-5b79-af82-ff1385104aa0"
1112
Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
1213
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
1314
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
@@ -25,6 +26,7 @@ Documenter = "1.11.4"
2526
KiteUtils = "0.10.7"
2627
LinearAlgebra = "1.10, 1.11"
2728
NLsolve = "4.5.1"
29+
NOMAD = "2.4.1"
2830
PRIMA = "0.2.2"
2931
Parameters = "0.12.3"
3032
Pkg = "1.10, 1.11"

scripts/autotune_nomad.jl

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# this script tunes the controller parameters (well, seven of them)
2+
# TODO: make sure that calling autotune does not make the performance worse
3+
# DONE: add the mean square of the acceleration to the damage metric
4+
using Pkg
5+
if ! ("ControlPlots" keys(Pkg.project().dependencies))
6+
using TestEnv; TestEnv.activate()
7+
using Test
8+
end
9+
using WinchControllers, KiteUtils, PRIMA, NOMAD, ControlPlots
10+
11+
TUNED::Bool = false
12+
load_settings("system.yaml")
13+
14+
function calc_force(v_wind, v_ro)
15+
(v_wind - v_ro)^2 * 4000.0 / 16.0
16+
end
17+
18+
function plot(lg::WCLogger)
19+
p1=plotx(lg.time, lg.v_wind, [lg.v_ro, lg.v_set_in], lg.f_err*0.001, lg.v_err, lg.acc, lg.force*0.001, lg.state,
20+
title="Winch controller test, all controllers active",
21+
ylabels=["v_wind [m/s]", "v_reel_out [m/s]", "f_err [kN]", "v_error [m/s]", "acc [m/s²]", "force [kN]", "state"],
22+
ysize=10,
23+
labels=["v_wind", ["v_reel_out", "v_set_in"]],
24+
fig="test_winchcontroller",)
25+
display(p1)
26+
end
27+
28+
function simulate(wcs::WCSettings; return_lg::Bool = false)
29+
if TUNED
30+
set = load_settings("system_tuned.yaml")
31+
else
32+
set = load_settings("system.yaml")
33+
end
34+
35+
# define the simulation parameters
36+
DURATION = 10.0
37+
V_WIND_MAX = 9.0 # max wind speed of test wind
38+
V_WIND_MIN = 0.0 # min wind speed of test wind
39+
FREQ_WIND = 0.25 # frequency of the triangle wind speed signal
40+
41+
# create the logger
42+
lg::WCLogger = WCLogger(DURATION, wcs.dt, set.max_force, wcs.max_acc, wcs.damage_factor)
43+
44+
STARTUP = get_startup(wcs, length(lg))
45+
V_WIND = STARTUP .* get_triangle_wind(wcs, V_WIND_MIN, V_WIND_MAX, FREQ_WIND, length(lg))
46+
47+
# create and initialize winch controller
48+
wc = WinchController(wcs)
49+
winch = WinchControllers.Winch(wcs, set)
50+
f_low = wcs.f_low
51+
52+
for i in 1:length(lg)
53+
# model
54+
v_wind = V_WIND[i]
55+
v_act = get_speed(winch)
56+
force = calc_force(v_wind, v_act)
57+
set_force(winch, force)
58+
59+
# controller
60+
v_set_out = calc_v_set(wc, v_act, force, f_low)
61+
62+
# update model input
63+
set_v_set(winch, v_set_out)
64+
65+
# run integration step
66+
on_timer(winch)
67+
on_timer(wc)
68+
69+
# get values for logging and log them
70+
status = get_status(wc)
71+
log(lg; v_wind, v_ro=v_act, acc=get_acc(winch), state=get_state(wc), reset=status[1], active=status[2], force=status[3],
72+
f_set=status[4], f_err=get_f_err(wc), v_err=get_v_err(wc), v_set=get_v_set(wc), v_set_out, v_set_in=get_v_set_in(wc))
73+
end
74+
if return_lg
75+
return wcs, lg
76+
end
77+
# calculate the performance metrics
78+
-gamma(lg; rms=true)
79+
end
80+
81+
82+
function simulate_sc(x::Vector; return_lg::Bool = false)
83+
wcs = WCSettings(dt=0.02)
84+
update(wcs)
85+
wcs.test = true
86+
wcs.i_speed = x[1] # set the speed controller gain
87+
wcs.p_speed = x[2] # set the speed controller proportional gain
88+
wcs.t_blend = x[3] # set the blending time for switching between controllers
89+
simulate(wcs; return_lg)
90+
end
91+
92+
function eval_fct(x)
93+
bb_outputs = [simulate_sc(x)]
94+
success = true
95+
count_eval = true
96+
return (success, count_eval, bb_outputs)
97+
end
98+
99+
function simulate_lfc(x::Vector{Cdouble}; return_lg::Bool = false)
100+
wcs = WCSettings(dt=0.02)
101+
update(wcs)
102+
wcs.test = true
103+
wcs.pf_low = x[1] # set the lower force controller gain
104+
wcs.if_low = x[2] # set the lower force controller integral gain
105+
simulate(wcs; return_lg)
106+
end
107+
108+
function simulate_ufc(x::Vector{Cdouble}; return_lg::Bool = false)
109+
wcs = WCSettings(dt=0.02)
110+
update(wcs)
111+
wcs.test = true
112+
wcs.pf_high = x[1] # set the higher force controller gain
113+
wcs.if_high = x[2] # set the higher force controller integral gain
114+
simulate(wcs; return_lg)
115+
end
116+
117+
function autotune(controller::WinchControllerState)
118+
global x, info, lg, TUNED, result
119+
if TUNED
120+
load_settings("system_tuned.yaml")
121+
else
122+
load_settings("system.yaml")
123+
end
124+
wcs = WCSettings(dt=0.02)
125+
update(wcs)
126+
wcs.test = true
127+
if controller == wcsSpeedControl
128+
println("Autotuning speed controller...")
129+
# # Define the parameters for the autotuning
130+
# x0 = [wcs.p_speed, wcs.i_speed, wcs.t_blend] # initial guess for the speed controller gain
131+
# x, info = bobyqa(simulate_sc, x0;
132+
# xl = 0.75 .* x0,
133+
# xu = 1.5 .* x0,
134+
# rhobeg = maximum([1e-4, minimum(x0)/4]),
135+
# npt=10,
136+
# maxfun = 500
137+
# )
138+
x0 = [wcs.p_speed, wcs.i_speed, wcs.t_blend] # initial guess for the speed controller gain
139+
140+
pb = NomadProblem(3, # number of inputs of the blackbox
141+
1, # number of outputs of the blackbox
142+
["OBJ"], # type of outputs of the blackbox
143+
eval_fct;
144+
lower_bound = 0.75 .* x0,
145+
upper_bound = 1.5 .* x0)
146+
result = solve(pb, x0)
147+
x = result.x_best_feas
148+
elseif controller == wcsLowerForceLimit
149+
println("Autotuning lower force limit controller...")
150+
# Define the parameters for the autotuning
151+
x0 = [maximum([1e-4, wcs.pf_low]), wcs.if_low] # initial guess for the speed controller gain
152+
153+
x, info = bobyqa(simulate_lfc, x0;
154+
xl = 0.25 .* x0,
155+
xu = 2.0 .* x0,
156+
rhobeg = maximum([1e-4, minimum(x0)/4]),
157+
maxfun = 500
158+
)
159+
elseif controller == wcsUpperForceLimit
160+
println("Autotuning upper force control...")
161+
# Define the parameters for the autotuning
162+
x0 = [maximum([2e-5, wcs.pf_high]), wcs.if_high] # initial guess for the speed controller gain
163+
x, info = bobyqa(simulate_lfc, x0;
164+
xl = 0.25 .* x0,
165+
xu = 2.0 .* x0,
166+
rhobeg = maximum([2e-5, minimum(x0)/4]),
167+
maxfun = 500
168+
)
169+
else
170+
error("Unknown controller state: $controller")
171+
return
172+
end
173+
174+
println("Autotuning results: $x")
175+
# println("Iterations: $(info.nf)")
176+
# println(PRIMA.reason(info.status))
177+
178+
if true
179+
println("Running simulation with tuned parameters...")
180+
TUNED = true
181+
if controller == wcsSpeedControl
182+
wcs, lg = simulate_sc(x; return_lg=true)
183+
elseif controller == wcsLowerForceLimit
184+
wcs, lg = simulate_lfc(x; return_lg=true)
185+
elseif controller == wcsUpperForceLimit
186+
wcs, lg = simulate_ufc(x; return_lg=true)
187+
end
188+
189+
println("\nPerformance of force controllers: $(round(100*(1-f_err(lg)), digits=2)) %")
190+
println("Performance of speed controller: $(round(100*(1-v_err(lg)), digits=2)) %")
191+
println("Damage: $(round(100*(damage(lg)), digits=2)) %")
192+
println("Damage with rms: $(round(100*(damage(lg; rms=true)), digits=2)) %")
193+
println("Combined performance γ: $(round(-100*result.bbo_best_feas[1], digits=2)) %")
194+
return wcs
195+
else
196+
println("Autotuning failed: $(PRIMA.reason(info.status))")
197+
return nothing
198+
end
199+
end
200+
201+
function copy_settings()
202+
cp("data/wc_settings.yaml", "data/wc_settings_tuned.yaml"; force=true)
203+
end
204+
function change_value(lines, varname, value::Union{Integer, Float64})
205+
KiteUtils.change_value(lines, varname, repr(round(value, digits=4)))
206+
end
207+
function update_settings(wcs::WCSettings)
208+
lines = KiteUtils.readfile("data/wc_settings_tuned.yaml")
209+
lines = change_value(lines, "i_speed:", wcs.i_speed)
210+
lines = change_value(lines, "p_speed:", wcs.p_speed)
211+
lines = change_value(lines, "t_blend:", wcs.t_blend)
212+
lines = change_value(lines, "pf_low:", wcs.pf_low)
213+
lines = change_value(lines, "if_low:", wcs.if_low)
214+
lines = change_value(lines, "pf_high:", wcs.pf_high)
215+
lines = change_value(lines, "if_high:", wcs.if_high)
216+
KiteUtils.writefile(lines, "data/wc_settings_tuned.yaml")
217+
end
218+
219+
function tune_all()
220+
wcs = autotune(wcsSpeedControl)
221+
if ! isnothing(wcs)
222+
copy_settings()
223+
update_settings(wcs)
224+
println()
225+
wcs = autotune(wcsLowerForceLimit)
226+
if ! isnothing(wcs)
227+
update_settings(wcs)
228+
println()
229+
wcs = autotune(wcsUpperForceLimit)
230+
if ! isnothing(wcs)
231+
update_settings(wcs)
232+
end
233+
end
234+
@info "Tuned settings saved to data/wc_settings_tuned.yaml"
235+
end
236+
end
237+
238+
tune_all()
239+
tune_all()
240+
241+
242+
# autotune(wcsUpperForceControl)

0 commit comments

Comments
 (0)