Settings
All settings of a run are YAML files in the data/ directory of this package. The example scripts call set_data_path on that directory, so the kite model reads them from here instead of from its own data directory. You can change the wind, the tether, the winch or the controller tuning without editing V3Kite.
The system project
A run starts from one system project, a file data/system_*.yaml. It holds no settings of its own. Its system: section lists the YAML files that together describe the complete system and its controllers. For example, data/system_reelout_180m.yaml:
system:
sim_settings: "settings_reelout_180m.yaml"
wc_settings: "wc_settings.yaml"
fc_settings: "fc_settings_reelout.yaml"
traj_opt_settings: "traj_opt.yaml"
winch_table: "winch_table.yaml"
turn_rate_coeffs: "turn_rate_coeffs.yaml"
course_loop_model: "course_loop_model.yaml"
kite_correction: "kite_correction_measured.csv"
kite_settings: "kite_settings_psm.yaml"
structural_geometry: "struc_geometry.yaml"
aero_geometry: "cfd_aero_geometry.yaml"
vsm_settings: "vsm_settings.yaml"
settle_settings: "settle_settings_default.yaml"
heading_settings: "heading_settings_psm.yaml"project_file resolves a project name such as "system_reelout_180m.yaml" to this package's data/ directory. The functions fc_settings, turn_rate_coeffs_file, course_loop_model_file, kite_correction_file, winch_table_file and traj_opt_settings_file each return one entry of the system: section, in the same way as KiteUtils.wc_settings.
These projects are included (all names without the .yaml extension):
| Project | Run | sim_settings | fc_settings |
|---|---|---|---|
system_fig8_150m | fig8, 150 m | settings_fig8_150m | fc_settings_fig8_150m |
system_fig8_200m | fig8, 200 m | settings_fig8_200m | fc_settings |
system_fig8_300m | fig8, 300 m | settings_fig8_300m | fc_settings |
system_reelout_maasvlakte | reel-out, 150 m | settings_reelout_150m | fc_settings_reelout |
system_reelout_180m | reel-out, 180 m | settings_reelout_180m | fc_settings_reelout |
system_reelout_cabauw | reel-out, Cabauw | settings_reelout_cabauw | fc_settings_reelout |
system_fig8_200m.yaml is the default project: project_file uses it when no name is given, and the turn-rate table and the course-loop model are loaded against it when the package loads.
The files a project names
sim_settings→settings_*.yaml, read intoKiteUtils.Settings: the plant and the simulation. Wind speed and profile, tether length, mass, winch model, KCU, solver,sim_timeandsample_freq(the time step).wc_settings→wc_settings.yaml, read intoWCSettings: the winch controllers. The torque block (V3Kite's position and force modes) and the speed block (WinchControllers.jl's reel-out law and its force limiters).fc_settings→fc_settings*.yaml, read intoFC_Settings: the flight controller. Entry state machine, pattern geometry, heading/course PID, feed-forward, reel-out phases and the run's pass criteria.traj_opt_settings→traj_opt.yaml, read intoTrajOptSettings: the AWETrim client, one section per part: server, guess, depower seed, pattern box, gates and re-optimization; only used bysimple_opt_fig8.jlandsimple_opt_reelout.jl.winch_table→winch_table.yaml, read bywinch_f_lowandwinch_force_limit: wind-dependent winch-law parameters. Reel-out projects only.turn_rate_coeffs→turn_rate_coeffs.yaml, read byturn_rate_coeffs: the identified turn-rate law (c1,c2,delay) per body damping and depower.course_loop_model→course_loop_model.yaml, read intoCourseLoopModel: the other identified parameters of the linear course-loop model of the stability analysis (tape lag, scaling of the kite's dead time and lag, pattern law, kite correction). Every key is required.kite_correction→kite_correction_measured.csv, read withload_course_correction: the measured kite correction, gain and phase over frequency, written byexamples/identify_kite_correction.jl; the guided-loop margins ofstability_opt_reelout.jlare also evaluated with it.kite_settings→kite_settings_psm*.yamlin this package, read into V3Kite'sV3KiteConfig: wing model, aerodynamics mode, backend and in-flight damping.structural_geometry,aero_geometry,vsm_settings,settle_settings,heading_settings→ V3Kite's own files: geometry, polars, VSM and settling settings, read from V3Kite's data directory.
V3Kite looks for each of these files beside the project first and in its own data directory after. The figure-of-eight projects and system_reelout_180m.yaml name kite_settings_psm.yaml, a local copy of V3Kite's file, so an upstream change does not reach these runs unnoticed. system_reelout_maasvlakte.yaml and system_reelout_cabauw.yaml name kite_settings_psm_kernel.yaml, a local variant whose only difference in effect is analytic_jacobian: true. The vsm_interval in these files is not read by the runs of this package: they pass run.vsm_interval of fc_settings to step!.
Not named by any project:
gui.yaml: the choices of the example menu (project, simulation time, plots, wind speed), see State of the example menu. It is created fromgui.yaml.defaulton first use and is not under version control.
Rules shared by the settings files
- Every key of
traj_opt.yamlis a field of the struct it is loaded into. A missing key falls back to the struct default; an unknown key is an error (seeload_yaml_fields!). fc_settings*.yamlhas one section per part ofFC_Settings:course,feedforward,pattern,wind_ramp,winch,reeloutandrun. Each key of a section is a field of that part, with the same rules. A figure-of-eight run can leave out thereeloutsection. Files archived before this layout, with all keys directly underfc_settings:, still load.- The struct docstrings (on the API pages) say in one line what a field is. The comments in the YAML files give the longer notes and the reason for the value chosen there. The history of the tuning is in docs/fig8tuninglog.md.
fc_settings_fig8_150m.yamlandfc_settings_reelout.yamlstarted as copies offc_settings.yaml. Keys they share must be kept in step by hand.- An example script can override single fields for one run without editing a file, see
apply_overrides!.
Example: fc_settings_reelout.yaml
The flight-controller settings of all reel-out projects, shown here as shipped:
# Flight-controller settings flown by examples/simple_reelout.jl and
# simple_opt_reelout.jl, named by the system_reelout_*.yaml projects next to it.
# A copy of fc_settings.yaml (simple_fig8.jl) with `compliance: 0`: REEL_OUT and
# V3Kite's FORCE mode both drive the winch, and simple_reelout.jl errors rather
# than picking one. Each section is a part of `FC_Settings` (src/fc_settings.jl)
# and each key a field of that part. The docstrings there stay on one line, the
# comments below carry the longer notes; a missing key falls back to the struct default,
# an unknown key is an error. The plant (sim_time, sample_freq, v_wind,
# l_tethers) is in the system project's settings file, the winch gains in
# wc_settings.yaml. Tuning history: docs/fig8_tuning_log.md.
fc_settings:
course: # heading/course loop: entry state machine, depower, PID, feedback, descent limiter
park_time: 2.0 # Park: zero steering while the transients decay [s]
chi_dive: -145.0 # Dive course; >90 descends, <90 climbs, 90 flat [deg]
chi_hold: -90.0 # Course commanded during the hold [deg]
dive_el_margin: 17.0 # Margin above el_center where the dive ends [deg]
hold_time: 0.8 # Duration of the hold [s]
fig8_d_gate: 4.0 # Cross-track error, transition -> fig8 [deg]
# 0.25 with the 73° relay sweeps' table; /1.084 = 0.23 with the low-elevation table, whose
# c1(depower_setpoint)/c1(entry_depower) is 1.084 x higher, so the entry flies as tuned (2026-09-29).
entry_gain: 0.23 # Factor on heading_p during the entry phases [-]
entry_depower: 0.34 # Depower during the entry phases [-]
depower_setpoint: 0.274 # Depower on the pattern; 0.278 is the curvature ceiling at 150 m [-]
depower_blend_time: 2.5 # Ramp of `rel_depower` to a new ladder target; 0 = step [s]
# heading_p +8 % for guided α 0.306 and lower RMS d (2026-09-29).
heading_p: 0.183805 # Gain at v_app_ref [-]
heading_i: false # Integral time [s], or false for no integral action
heading_d: 0.141 # Derivative time; raised for the guided disk margin (2026-09-28, 2026-09-29) [s]
heading_d_n: 2.0 # Derivative filter, max gain of the D path [-]
v_app_ref: 27.0 # Speed flown in phase 3; anchors the gain schedule [m/s]
v_app_min: 10.0 # Lower clamp on v_app, limits the gain boost [m/s]
v_kite_heading: 5.0 # At/below: pure heading feedback [m/s]
v_kite_course: 10.0 # At/above: pure course feedback [m/s]
fig8_pure_course: false # Course alone from phase 3 on; schedule governs entry
max_steering: 0.32 # Command limit; raising it is CLOSED, see the log [-]
entry_chi_max: 95.0 # Steepest course while off-path; 180 disables it [deg]
entry_d_gate: 12.0 # Cross-track error below which it is bypassed [deg]
entry_d_blend: 4.0 # Blend band above the gate, 0 = hard switch [deg]
entry_cut_margin: 30.0 # Distance from ±180° where chi_set's sign is noise [deg]
feedforward: # steering feed-forward from the path's curvature, phase 4 on
# 0.7 with the 73° relay sweeps' table (deleted 2026-10-01); x1.084 = 0.76 with the low-elevation
# table, turn_rate_coeffs.yaml, whose c1 at depower_setpoint is 1.084 x higher, so u_ff stays as
# tuned (2026-09-29).
ff_gain: 0.76 # Curvature feed-forward, u_ff = psi_dot_path/(c1 v_app); 0 = off, 1 = the law [-]
ff_lead_time: 0.35 # Read the path's course rate this far ahead of Q; ~the dead time [s]
ff_smooth: 6.0 # Arc the tangent change is averaged over [deg]
ff_tau: 0.2 # Low-pass on u_ff and the chord correction; 0 = none [s]
ff_d_fade: 6.0 # Cross-track error at which the ff is fully off; fades from half [deg]
ff_err_fade: 60.0 # Course error at which the ff is fully off; fades from half [deg]
pattern: # pattern geometry and attractor; a SMALLER lemniscate is a TIGHTER one
f8_a: 20.0 # Width of the eight, azimuth spans ±A; sweep optimum [deg]
f8_b: 11.0 # Height, elevation spans ±B/2; picked for margin 1.07 [deg]
el_center: 18.0 # Centre elevation; lower turns easier, costs energy [deg]
# 8.0 -> 9.75 (2026-10-02, retune_guided.jl, target 0.4): worst guided disk margin of the 22
# scenarios 0.332 -> 0.401 (weak winds, where this floor sets the attractor); replays at
# maasvlakte 3.5/8.0 and cabauw 3.0 m/s pass all criteria, RMS d +20 - 29 %, power unchanged.
# 9.75 -> 8.25 (2026-10-03, retune_guided.jl tighten, floor 0.51): worst guided disk margin
# 0.523 -> 0.515, now maasvlakte 5 m/s; 8 m/s and up unchanged. Aim: lower RMS tracking error.
# Floor ∝ 1/L since 2026-10-03: a fixed arc of 25.3 m, 8.35° at 175 m (9.7° at 150 m, 3.8° at
# 380 m). Only attractor_dist * attractor_dist_ref_length matters; the smallest product keeping
# the worst guided margin of the 22 scenarios >= 0.51 is 8.31° x 175 m (the same at L_ref 150-300).
# Replays on the archived paths: RMS d -31 % maasvlakte 3.5, -28 % 5, -20 % 8, -25 % cabauw 4,
# -5 % 6, -3 % 9 m/s; power within 2 %, max force unchanged, all criteria passed.
attractor_dist: 8.35 # Arc distance Q -> attractor at attractor_dist_ref_length; the FLOOR under a lead time [deg]
attractor_dist_ref_length: 175.0 # Tether length where attractor_dist holds, floor ∝ 1/L; 0 = fixed [m]
# attractor_lead_time: ω_g below the course loop, guided disk margin >= 0.30 with c3 (2026-09-28);
# 0.96 -> 1.05 (2026-10-03): Cabauw 10 m/s guided disk margin 0.477 -> 0.534, RMS cross-track error 1.27 -> 1.21°.
attractor_lead_time: 1.05 # Lead as flight time, arc = t*v_app/L; 0 = off [s]
reacquire_margin: 6.0 # Global best must beat the in-window best by this [deg]
up_loops: false # Up-loops instead of down-loops; down crosses the centre
winch: # compliance of the force-mode winch (its gains are in wc_settings.yaml) and force guards
compliance: 0.0 # Fixed at POSITION mode; REEL_OUT needs the drum free [-]
entry_f_min: 350.0 # Entry-guard (guard_lfc) force floor, phases 0-2; not wc's f_low [N]
first_lap_force_frac: 0.93 # f_high x this in lap 1 AND for the startup solve; 1.0 = no lap-1 de-rating [-]
reelout: # REEL_OUT winch and phase 5; kv/f_low/f_high/v_sat are in wc_settings.yaml
reelout_l_max: 380.0 # Length at which reel-out stops; AWETrim's reopt ceiling is ~325 m [m]
n_fig_eight: 0 # Laps after which reel-out stops; 0 = length only [-]
reelout_softstart: 12.0 # Ramps the COMMANDED speed 0 -> v_set over this long [s]
reelout_softstop: 1.5 # Linear decel trigger at the far end [s]
reelout_delay: 4.2 # Wait after phase 3 before reel-out starts [s]
reelout_f_trigger: 6400.0 # Force that releases reel-out EARLY; Inf disables it [N]
final_time: 30.0 # Sim time flown in phase 5 before the run ends; Inf = full run [s]
depower_final: 0.35 # Flown from phase 5; tuned to hold ~3458 N at 6 m/s [-]
depower_final_max: 0.42 # Ceiling of the phase-5 force limiter; = depower_final is OFF [-]
depower_final_f_target: 7500.0 # Force the limiter holds, under 8400 N by the lobe swing [N]
depower_final_f_gain: 6.0e-5 # Limiter integrator gain, depower per N per s [1/(N s)]
depower_final_f_gain_stop: 1.0e-4 # Same during the soft-stop ramp: 0.35 -> 0.40 in 3 s [1/(N s)]
el_offset_final: 1.0 # Extra lift of the path once reel-out ends [deg]
el_offset_lead: 8.0 # How early the lift starts; gets it past the phase-5 gate [s]
final_margin_min: 1.5 # Phase-5 path below this curvature margin falls back; 0 = off [-]
el_offset_wing: 1.0 # Extra lift at the LOBES, none in the centre [deg]
el_offset_wing_az: 10.0 # |azimuth| beyond which that lift is full [deg or fraction of A]
el_offset_wing_blend: 8.0 # Ramp width below it; NOT monotone, see the docstring [same units]
el_offset_wing_mode: "azimuth" # azimuth (deg) | azimuth_frac (of the path's own A)
low_wind: # per wind speed at low_wind_height, linear in between, first row held below; off from the last row on
# Flown 2026-10-02, the guided disk margin was 0.41-0.44 at 150 m: Maasvlakte 3.5 m/s (4.51 at 100 m),
# Maasvlakte 4 m/s (5.15), Cabauw 3 m/s (5.80); Maasvlakte 5 m/s (6.44) is robust as the files fly it.
# The last row is the files' own values: l_tethers, traj_opt's guess_el_center, v_app_min, el_offset_final.
low_wind_height: 100.0 # Height of the wind the schedule is keyed on [m]
low_wind_speeds: [4.51, 5.15, 5.80, 6.40] # Wind speed at low_wind_height, ascending [m/s]
low_wind_l_tether: [195.0, 195.0, 195.0, 150.0] # Tether length reel-out starts at; less guidance phase lag [m]
low_wind_guess_el_center: [25.0, 27.0, 27.0, 29.0] # Startup guess; 29° at 195 m lands in a 470 W optimum [deg]
low_wind_v_app_min: [8.0, 10.0, 10.0, 10.0] # Gain-schedule floor; 8 lifts the bins flown at v_a < 10 m/s [m/s]
low_wind_el_offset_final: [1.5, 1.0, 1.0, 1.0] # Phase-5 lift; 1.5 keeps Maasvlakte 3.5 above min_elevation [deg]
run: # simulation conditions and pass criteria
vsm_interval: 5 # Steps between VSM aero updates, 1 = tightest; at 10 the identification flights sink at depower 0.375 (2026-10-02) [-]
elevation: 73.0 # Where init settles the kite; in the settled-state cache key [deg]
warmup_time: 2.0 # Discarded warm-up run, right after `init` [s]
body_damping: [0.0, 0.0, 40.0] # Per axis; the turn_rate_coeffs key (settles to 0.8x)
v_app_abort: 55.0 # Stop the run above this apparent wind speed [m/s]
entry_time: 62.0 # Settle time after park_time before the metrics [s]
min_elevation: 6.5 # Floor criterion over the WHOLE run; also the reopt install gate [deg]
min_span_frac: 0.7 # Pattern-SIZE criterion, fraction of f8_a / f8_b [-]