diff --git a/.gitignore b/.gitignore index 142b4f47..6cd5e8fe 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ Manifest-v1.12.toml .vscode/settings.json .JETLSConfig.toml Manifest-v1.11.toml +docs/src/heading.pdf diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b858215..979c7465 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## KiteUtils v0.11.8 05-05-2026 +### Added +- add `azimuth_rate` to `SysState`, including logging, display, and Arrow load/save support + ## KiteUtils v0.11.7 20-04-2026 ### Added - add version 4 of RecursiveArrayTools in compat diff --git a/Project.toml b/Project.toml index 999a379f..240c7fd7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "KiteUtils" uuid = "90980105-b163-44e5-ba9f-8b1c83bb0533" authors = ["Uwe Fechner and contributors"] -version = "0.11.7" +version = "0.11.8" [workspace] projects = ["examples", "test", "docs"] diff --git a/docs/src/examples.md b/docs/src/examples.md index a22756b7..bcc32293 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -127,22 +127,71 @@ julia> syslog=log.syslog You can acces this array by index: ```julia syslog[end] -time [s]: 10.0 -orient [w,x,y,z]: Float32[0.5, 0.5, -0.5, -0.5] -elevation [rad]: 0.64350116 -azimuth [rad]: 0.0 -l_tether [m]: 0.0 -v_reelout [m/s]: 0.0 -force [N]: 0.0 -depower [-]: 0.0 -steering [-]: 0.0 -heading [rad]: 0.0 -course [rad]: 0.0 -v_app [m/s]: 0.0 -vel_kite [m/s]: Float32[0.0, 0.0, 0.0] -X [m]: Float32[0.0, 1.6666666, 3.3333333, 5.0, 6.6666665, 8.333333, 10.0] -Y [m]: Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] -Z [m]: Float32[0.0, 0.15380114, 0.6194867, 1.4100224, 2.5474184, 4.063342, 6.0000005] +time [s]: 10.0 +t_sim [s]: 0.012 +sys_state [-]: 0 +cycle [-]: 0 +fig_8 [-]: 0 +e_mech [Wh]: 0.0 +orient [-]: Float32[0.5, 0.5, -0.5, -0.5] +turn_rates [rad/s]:Float32[0.0, 0.0, 0.0] +elevation [rad]: 0.5404195 +azimuth [rad]: 0.0 +azimuth_rate [rad/s]:0.0 +l_tether [m]: Float32[0.0, 0.0, 0.0, 0.0] +v_reelout [m/s]: Float32[0.0, 0.0, 0.0, 0.0] +winch_force [N]: Float32[0.0, 0.0, 0.0, 0.0] +depower [0..1]: 0.0 +steering [-1..1]: 0.0 +kcu_steering [-1..1]:0.0 +set_steering [-1..1]:0.0 +heading [rad]: 0.0 +heading_rate [rad/s]:0.0 +course [rad]: 0.0 +bearing [rad]: 0.0 +attractor [rad]: Float32[0.0, 0.0] +v_app [m/s]: 0.0 +v_wind_gnd [m/s]: Float32[10.4855, 0.0, -3.08324] +v_wind_200m [m/s]: Float32[10.4855, 0.0, -3.08324] +v_wind_kite [m/s]: Float32[10.4855, 0.0, -3.08324] +AoA [rad]: 0.0 +side_slip [rad]: 0.0 +alpha3 [rad]: 0.0 +alpha4 [rad]: 0.0 +CL2 [-]: 0.0 +CD2 [-]: 0.0 +aero_force_b [N]: Float32[0.0, 0.0, 0.0] +aero_moment_b [Nm]:Float32[0.0, 0.0, 0.0] +tether_induced_force [N]:Float32[0.0, 0.0, 0.0] +tether_induced_moment [Nm]:Float32[0.0, 0.0, 0.0] +twist_angles [rad]:Float32[0.0, 0.0, 0.0, 0.0] +vel_kite [m/s]: Float32[0.0, 0.0, 0.0] +acc [m/s²]: 0.0 +X [m]: Float32[0.0, 1.6666666, 3.3333333, 5.0, 6.6666665, 8.333333, 10.0] +Y [m]: Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +Z [m]: Float32[0.0, 0.15380114, 0.6194867, 1.4100224, 2.5474184, 4.063342, 6.0000005] +set_torque [Nm]: Float32[0.0, 0.0, 0.0, 0.0] +set_speed [m/s]: Float32[0.0, 0.0, 0.0, 0.0] +set_force [N]: Float32[0.0, 0.0, 0.0, 0.0] +roll [rad]: 0.0 +pitch [rad]: 0.0 +yaw [rad]: 0.0 +var_01 [-]: 0.0 +var_02 [-]: 0.0 +var_03 [-]: 0.0 +var_04 [-]: 0.0 +var_05 [-]: 0.0 +var_06 [-]: 0.0 +var_07 [-]: 0.0 +var_08 [-]: 0.0 +var_09 [-]: 0.0 +var_10 [-]: 0.0 +var_11 [-]: 0.0 +var_12 [-]: 0.0 +var_13 [-]: 0.0 +var_14 [-]: 0.0 +var_15 [-]: 0.0 +var_16 [-]: 0.0 ``` But you can also access the syslog component wise: diff --git a/src/_demo_syslog.jl b/src/_demo_syslog.jl index bec9c96a..5e152043 100644 --- a/src/_demo_syslog.jl +++ b/src/_demo_syslog.jl @@ -24,6 +24,7 @@ function demo_syslog(P; duration=10) turn_rates_vec = Vector{MVector{3, MyFloat}}(undef, steps) elevation_vec = Vector{MyFloat}(undef, steps) azimuth_vec = Vector{MyFloat}(undef, steps) + azimuth_rate_vec = Vector{MyFloat}(undef, steps) l_tether_vec = Vector{MVector{4, MyFloat}}(undef, steps) v_reelout_vec = Vector{MVector{4, MyFloat}}(undef, steps) winch_force_vec = Vector{MVector{4, MyFloat}}(undef, steps) @@ -91,6 +92,7 @@ function demo_syslog(P; duration=10) turn_rates_vec[i+1] = state.turn_rates elevation_vec[i+1] = state.elevation azimuth_vec[i+1] = state.azimuth + azimuth_rate_vec[i+1] = state.azimuth_rate l_tether_vec[i+1] = state.l_tether v_reelout_vec[i+1] = state.v_reelout winch_force_vec[i+1] = state.winch_force @@ -147,14 +149,14 @@ function demo_syslog(P; duration=10) var_16_vec[i+1] = state.var_16 end StructArray{SysState{P}}((time_vec, t_sim_vec, sys_state_vec, cycle_vec, fig_8_vec, e_mech_vec, - orient_vec, turn_rates_vec, elevation_vec, azimuth_vec, l_tether_vec, v_reelout_vec, - winch_force_vec, depower_vec, steering_vec, kcu_steering_vec, set_steering_vec, heading_vec, - heading_rate_vec, course_vec, bearing_vec, attractor_vec, v_app_vec, v_wind_gnd_vec, - v_wind_200m_vec, v_wind_kite_vec, AoA_vec, side_slip_vec, alpha3_vec, alpha4_vec, - CL2_vec, CD2_vec, aero_force_b_vec, aero_moment_b_vec, tether_induced_force_vec, tether_induced_moment_vec, - twist_angles_vec, vel_kite_vec, acc_vec, X_vec, Y_vec, Z_vec, - set_torque_vec, set_speed_vec, set_force_vec, roll_vec, pitch_vec, yaw_vec, - var_01_vec, var_02_vec, var_03_vec, var_04_vec, var_05_vec, var_06_vec, - var_07_vec, var_08_vec, var_09_vec, var_10_vec, var_11_vec, var_12_vec, - var_13_vec, var_14_vec, var_15_vec, var_16_vec)) + orient_vec, turn_rates_vec, elevation_vec, azimuth_vec, azimuth_rate_vec, l_tether_vec, + v_reelout_vec, winch_force_vec, depower_vec, steering_vec, kcu_steering_vec, set_steering_vec, + heading_vec, heading_rate_vec, course_vec, bearing_vec, attractor_vec, v_app_vec, + v_wind_gnd_vec, v_wind_200m_vec, v_wind_kite_vec, AoA_vec, side_slip_vec, alpha3_vec, + alpha4_vec, CL2_vec, CD2_vec, aero_force_b_vec, aero_moment_b_vec, tether_induced_force_vec, + tether_induced_moment_vec, twist_angles_vec, vel_kite_vec, acc_vec, X_vec, Y_vec, + Z_vec, set_torque_vec, set_speed_vec, set_force_vec, roll_vec, pitch_vec, + yaw_vec, var_01_vec, var_02_vec, var_03_vec, var_04_vec, var_05_vec, + var_06_vec, var_07_vec, var_08_vec, var_09_vec, var_10_vec, var_11_vec, + var_12_vec, var_13_vec, var_14_vec, var_15_vec, var_16_vec)) end diff --git a/src/_load_log.jl b/src/_load_log.jl index 50d0318f..3c198446 100644 --- a/src/_load_log.jl +++ b/src/_load_log.jl @@ -10,7 +10,7 @@ Read a log file that was saved as .arrow file. """ -load_log(_, filename::String) = load_log(filename) +load_log(P, filename::String) = load_log(filename) function load_log(filename::String; path="") if path == "" path = DATA_PATH[1] @@ -45,16 +45,17 @@ function load_log(filename::String; path="") # example_metadata = KiteUtils.Arrow.getmetadata(table.var_01) syslog = StructArray{SysState{P}}((table.time, table.t_sim, table.sys_state, table.cycle, table.fig_8, table.e_mech, table.orient, table.turn_rates, table.elevation, table.azimuth, - table.l_tether, table.v_reelout, table.winch_force, table.depower, table.steering, - table.kcu_steering, table.set_steering, table.heading, table.heading_rate, table.course, - table.bearing, table.attractor, table.v_app, table.v_wind_gnd, table.v_wind_200m, - table.v_wind_kite, table.AoA, table.side_slip, table.alpha3, table.alpha4, - table.CL2, table.CD2, table.aero_force_b, table.aero_moment_b, table.tether_induced_force, - table.tether_induced_moment, table.twist_angles, table.vel_kite, table.acc, table.X, - table.Y, table.Z, table.set_torque, table.set_speed, table.set_force, - table.roll, table.pitch, table.yaw, table.var_01, table.var_02, - table.var_03, table.var_04, table.var_05, table.var_06, table.var_07, - table.var_08, table.var_09, table.var_10, table.var_11, table.var_12, - table.var_13, table.var_14, table.var_15, table.var_16)) + table.azimuth_rate, table.l_tether, table.v_reelout, table.winch_force, table.depower, + table.steering, table.kcu_steering, table.set_steering, table.heading, table.heading_rate, + table.course, table.bearing, table.attractor, table.v_app, table.v_wind_gnd, + table.v_wind_200m, table.v_wind_kite, table.AoA, table.side_slip, table.alpha3, + table.alpha4, table.CL2, table.CD2, table.aero_force_b, table.aero_moment_b, + table.tether_induced_force, table.tether_induced_moment, table.twist_angles, table.vel_kite, table.acc, + table.X, table.Y, table.Z, table.set_torque, table.set_speed, + table.set_force, table.roll, table.pitch, table.yaw, table.var_01, + table.var_02, table.var_03, table.var_04, table.var_05, table.var_06, + table.var_07, table.var_08, table.var_09, table.var_10, table.var_11, + table.var_12, table.var_13, table.var_14, table.var_15, table.var_16 + )) return SysLog{P}(basename(fullname[1:end-6]), colmeta, syslog) end diff --git a/src/_log.jl b/src/_log.jl index 5c6c9fa4..166b58d2 100644 --- a/src/_log.jl +++ b/src/_log.jl @@ -26,6 +26,7 @@ function log!(logger::Logger, state::SysState) logger.turn_rates_vec[i] .= state.turn_rates logger.elevation_vec[i] = state.elevation logger.azimuth_vec[i] = state.azimuth + logger.azimuth_rate_vec[i] = state.azimuth_rate logger.l_tether_vec[i] .= state.l_tether logger.v_reelout_vec[i] .= state.v_reelout logger.winch_force_vec[i] .= state.winch_force diff --git a/src/_logger.jl b/src/_logger.jl index 53683e81..78dfa1f7 100644 --- a/src/_logger.jl +++ b/src/_logger.jl @@ -31,6 +31,7 @@ $(TYPEDFIELDS) turn_rates_vec::Vector{MVector{3, MyFloat}} = [zero(MVector{3, MyFloat}) for _ in 1:Q] elevation_vec::Vector{MyFloat} = zeros(MyFloat, Q) azimuth_vec::Vector{MyFloat} = zeros(MyFloat, Q) + azimuth_rate_vec::Vector{MyFloat} = zeros(MyFloat, Q) l_tether_vec::Vector{MVector{4, MyFloat}} = [zero(MVector{4, MyFloat}) for _ in 1:Q] v_reelout_vec::Vector{MVector{4, MyFloat}} = [zero(MVector{4, MyFloat}) for _ in 1:Q] winch_force_vec::Vector{MVector{4, MyFloat}} = [zero(MVector{4, MyFloat}) for _ in 1:Q] diff --git a/src/_save_log.jl b/src/_save_log.jl index 0c3009af..f7566f74 100644 --- a/src/_save_log.jl +++ b/src/_save_log.jl @@ -59,6 +59,7 @@ function save_log(logger::Logger, name="sim_log", compress=true; resize!(logger.turn_rates_vec, nl) resize!(logger.elevation_vec, nl) resize!(logger.azimuth_vec, nl) + resize!(logger.azimuth_rate_vec, nl) resize!(logger.l_tether_vec, nl) resize!(logger.v_reelout_vec, nl) resize!(logger.winch_force_vec, nl) diff --git a/src/_show.jl b/src/_show.jl index 8ad62e75..ab9db956 100644 --- a/src/_show.jl +++ b/src/_show.jl @@ -16,6 +16,7 @@ function Base.show(io::IO, st::SysState) println(io, "turn_rates [rad/s]:", st.turn_rates) println(io, "elevation [rad]: ", st.elevation) println(io, "azimuth [rad]: ", st.azimuth) + println(io, "azimuth_rate [rad/s]:", st.azimuth_rate) println(io, "l_tether [m]: ", st.l_tether) println(io, "v_reelout [m/s]: ", st.v_reelout) println(io, "winch_force [N]: ", st.winch_force) diff --git a/src/_syslog.jl b/src/_syslog.jl index 321480bc..6782dc57 100644 --- a/src/_syslog.jl +++ b/src/_syslog.jl @@ -9,15 +9,16 @@ function syslog(logger::Logger) l = logger StructArray{SysState{l.points}}((l.time_vec, l.t_sim_vec, l.sys_state_vec, l.cycle_vec, l.fig_8_vec, l.e_mech_vec, l.orient_vec, l.turn_rates_vec, l.elevation_vec, l.azimuth_vec, - l.l_tether_vec, l.v_reelout_vec, l.winch_force_vec, l.depower_vec, l.steering_vec, - l.kcu_steering_vec, l.set_steering_vec, l.heading_vec, l.heading_rate_vec, l.course_vec, - l.bearing_vec, l.attractor_vec, l.v_app_vec, l.v_wind_gnd_vec, l.v_wind_200m_vec, - l.v_wind_kite_vec, l.AoA_vec, l.side_slip_vec, l.alpha3_vec, l.alpha4_vec, - l.CL2_vec, l.CD2_vec, l.aero_force_b_vec, l.aero_moment_b_vec, l.tether_induced_force_vec, - l.tether_induced_moment_vec, l.twist_angles_vec, l.vel_kite_vec, l.acc_vec, l.X_vec, - l.Y_vec, l.Z_vec, l.set_torque_vec, l.set_speed_vec, l.set_force_vec, - l.roll_vec, l.pitch_vec, l.yaw_vec, l.var_01_vec, l.var_02_vec, - l.var_03_vec, l.var_04_vec, l.var_05_vec, l.var_06_vec, l.var_07_vec, - l.var_08_vec, l.var_09_vec, l.var_10_vec, l.var_11_vec, l.var_12_vec, - l.var_13_vec, l.var_14_vec, l.var_15_vec, l.var_16_vec)) + l.azimuth_rate_vec, l.l_tether_vec, l.v_reelout_vec, l.winch_force_vec, l.depower_vec, + l.steering_vec, l.kcu_steering_vec, l.set_steering_vec, l.heading_vec, l.heading_rate_vec, + l.course_vec, l.bearing_vec, l.attractor_vec, l.v_app_vec, l.v_wind_gnd_vec, + l.v_wind_200m_vec, l.v_wind_kite_vec, l.AoA_vec, l.side_slip_vec, l.alpha3_vec, + l.alpha4_vec, l.CL2_vec, l.CD2_vec, l.aero_force_b_vec, l.aero_moment_b_vec, + l.tether_induced_force_vec, l.tether_induced_moment_vec, l.twist_angles_vec, l.vel_kite_vec, l.acc_vec, + l.X_vec, l.Y_vec, l.Z_vec, l.set_torque_vec, l.set_speed_vec, + l.set_force_vec, l.roll_vec, l.pitch_vec, l.yaw_vec, l.var_01_vec, + l.var_02_vec, l.var_03_vec, l.var_04_vec, l.var_05_vec, l.var_06_vec, + l.var_07_vec, l.var_08_vec, l.var_09_vec, l.var_10_vec, l.var_11_vec, + l.var_12_vec, l.var_13_vec, l.var_14_vec, l.var_15_vec, l.var_16_vec + )) end diff --git a/src/_sysstate.jl b/src/_sysstate.jl index 4a072567..8ad6f0a9 100644 --- a/src/_sysstate.jl +++ b/src/_sysstate.jl @@ -34,6 +34,8 @@ $(TYPEDFIELDS) elevation::MyFloat = 0 "azimuth angle in wind reference frame [rad]" azimuth::MyFloat = 0 + "azimuth rate [rad/s]" + azimuth_rate::MyFloat = 0 "tether length, tether 1 to 4 [m]" l_tether::MVector{4, MyFloat} = [0.0, 0.0, 0.0, 0.0] "reelout speed, tether 1 to 4 [m/s]" diff --git a/src/load_log.jl b/src/load_log.jl index f924202e..9a229f1d 100644 --- a/src/load_log.jl +++ b/src/load_log.jl @@ -47,6 +47,7 @@ function load_log(filename::String; path="", debug=false) cycle = Vector{Int16}(undef, n) fig_8 = Vector{Int16}(undef, n) turn_rates = Vector{Float32}(undef, n) + azimuth_rate = Vector{Float32}(undef, n) kcu_steering = Vector{Float32}(undef, n) set_steering = Vector{Float32}(undef, n) heading_rate = Vector{Float32}(undef, n) @@ -75,7 +76,9 @@ function load_log(filename::String; path="", debug=false) yaw = Vector{Float32}(undef, n) winch_force = Vector{MVector{4, Float32}}(undef, n) - for name in [:cycle, :fig_8, :turn_rates, :kcu_steering, + fill!(azimuth_rate, 0) + + for name in [:cycle, :fig_8, :turn_rates, :azimuth_rate, :kcu_steering, :set_steering, :heading_rate, :bearing, :attractor, :v_wind_gnd, :v_wind_200m, :v_wind_kite, :AoA, :side_slip, :alpha3, :alpha4, :CL2, :CD2, :aero_force_b, :aero_moment_b, :tether_induced_force, :tether_induced_moment, @@ -88,6 +91,8 @@ function load_log(filename::String; path="", debug=false) fig_8 = table.fig_8 elseif name == :turn_rates turn_rates = table.turn_rates + elseif name == :azimuth_rate + azimuth_rate = table.azimuth_rate elseif name == :kcu_steering kcu_steering = table.kcu_steering elseif name == :set_steering @@ -153,7 +158,7 @@ function load_log(filename::String; path="", debug=false) end syslog = StructArray{SysState{P}}((table.time, table.t_sim, table.sys_state, cycle, fig_8, table.e_mech, table.orient, turn_rates, table.elevation, table.azimuth, - table.l_tether, table.v_reelout, winch_force, table.depower, table.steering, + azimuth_rate, table.l_tether, table.v_reelout, winch_force, table.depower, table.steering, kcu_steering, set_steering, table.heading, heading_rate, table.course, bearing, attractor, table.v_app, v_wind_gnd, v_wind_200m, v_wind_kite, AoA, side_slip, alpha3, alpha4, diff --git a/src/logger.jl b/src/logger.jl index c4196a2c..c5b3a8fd 100644 --- a/src/logger.jl +++ b/src/logger.jl @@ -105,6 +105,9 @@ function import_log(filename) ss.orient = orient ss.elevation = row.elevation ss.azimuth = row.azimuth + if haskey(row, :azimuth_rate) + ss.azimuth_rate = row.azimuth_rate + end ss.l_tether[1] = row.l_tether ss.v_reelout[1] = row.v_reelout if haskey(row, :winch_force) diff --git a/src/sysstate.yaml b/src/sysstate.yaml index 083c20b4..06d85b0a 100644 --- a/src/sysstate.yaml +++ b/src/sysstate.yaml @@ -9,6 +9,7 @@ sysstate: turn_rates: "MVector{3, MyFloat}" # turn rates around the body fixed x, y and z axis [rad/s] elevation: "MyFloat" # elevation angle [rad] azimuth: "MyFloat" # azimuth angle in wind reference frame [rad] + azimuth_rate: "MyFloat" # azimuth rate [rad/s] l_tether: "MVector{4, MyFloat}" # tether length, tether 1 to 4 [m] v_reelout: "MVector{4, MyFloat}" # reelout speed, tether 1 to 4 [m/s] winch_force: "MVector{4, MyFloat}" # tether force at the winch, tether 1 to 4 [N] diff --git a/test/test-logfiles.jl b/test/test-logfiles.jl index 105fc591..105e3938 100644 --- a/test/test-logfiles.jl +++ b/test/test-logfiles.jl @@ -9,7 +9,7 @@ using KiteUtils, Test, StructArrays @test typeof(state) == SysState{7} @test state.X[end] == 10.0 @test all(state.pos[end] .≈ [10, 0, 6.0]) - @test_broken repr(state) == "time [s]: 0.0\nt_sim [s]: 0.012\nsys_state : 0\ne_mech [Wh]: 0.0\norient [w,x,y,z]: Float32[0.5, 0.5, -0.5, -0.5]\nelevation [rad]: 0.5404195\nazimuth [rad]: 0.0\nl_tether [m]: 0.0\nv_reelout [m/s]: 0.0\nforce [N]: 0.0\ndepower [-]: 0.0\nsteering [-]: 0.0\nheading [rad]: 0.0\ncourse [rad]: 0.0\nv_app [m/s]: 0.0\nvel_kite [m/s]: Float32[0.0, 0.0, 0.0]\nX [m]: Float32[10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0]\nY [m]: Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\nZ [m]: Float32[6.0000005, 6.0000005, 6.0000005, 6.0000005, 6.0000005, 6.0000005, 6.0000005]\nvar_01 : 0.0\nvar_02 : 0.0\nvar_03 : 0.0\nvar_04 : 0.0\nvar_05 : 0.0\nvar_06 : 0.0\nvar_07 : 0.0\nvar_08 : 0.0\nvar_09 : 0.0\nvar_10 : 0.0\nvar_11 : 0.0\nvar_12 : 0.0\nvar_13 : 0.0\nvar_14 : 0.0\nvar_15 : 0.0\nvar_16 : 0.0\n" + @test repr(state) == "time [s]: 0.0\nt_sim [s]: 0.012\nsys_state [-]: 0\ncycle [-]: 0\nfig_8 [-]: 0\ne_mech [Wh]: 0.0\norient [-]: Float32[0.5, 0.5, -0.5, -0.5]\nturn_rates [rad/s]:Float32[0.0, 0.0, 0.0]\nelevation [rad]: 0.5404195\nazimuth [rad]: 0.0\nazimuth_rate [rad/s]:0.0\nl_tether [m]: Float32[0.0, 0.0, 0.0, 0.0]\nv_reelout [m/s]: Float32[0.0, 0.0, 0.0, 0.0]\nwinch_force [N]: Float32[0.0, 0.0, 0.0, 0.0]\ndepower [0..1]: 0.0\nsteering [-1..1]: 0.0\nkcu_steering [-1..1]:0.0\nset_steering [-1..1]:0.0\nheading [rad]: 0.0\nheading_rate [rad/s]:0.0\ncourse [rad]: 0.0\nbearing [rad]: 0.0\nattractor [rad]: Float32[0.0, 0.0]\nv_app [m/s]: 0.0\nv_wind_gnd [m/s]: Float32[10.4855, 0.0, -3.08324]\nv_wind_200m [m/s]: Float32[10.4855, 0.0, -3.08324]\nv_wind_kite [m/s]: Float32[10.4855, 0.0, -3.08324]\nAoA [rad]: 0.0\nside_slip [rad]: 0.0\nalpha3 [rad]: 0.0\nalpha4 [rad]: 0.0\nCL2 [-]: 0.0\nCD2 [-]: 0.0\naero_force_b [N]: Float32[0.0, 0.0, 0.0]\naero_moment_b [Nm]:Float32[0.0, 0.0, 0.0]\ntether_induced_force [N]:Float32[0.0, 0.0, 0.0]\ntether_induced_moment [Nm]:Float32[0.0, 0.0, 0.0]\ntwist_angles [rad]:Float32[0.0, 0.0, 0.0, 0.0]\nvel_kite [m/s]: Float32[0.0, 0.0, 0.0]\nacc [m/s²]: 0.0\nX [m]: Float32[0.0, 1.6666666, 3.3333333, 5.0, 6.6666665, 8.333333, 10.0]\nY [m]: Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\nZ [m]: Float32[0.0, 0.15380114, 0.6194867, 1.4100224, 2.5474184, 4.063342, 6.0000005]\nset_torque [Nm]: Float32[0.0, 0.0, 0.0, 0.0]\nset_speed [m/s]: Float32[0.0, 0.0, 0.0, 0.0]\nset_force [N]: Float32[0.0, 0.0, 0.0, 0.0]\nroll [rad]: 0.0\npitch [rad]: 0.0\nyaw [rad]: 0.0\nvar_01 [-]: 0.0\nvar_02 [-]: 0.0\nvar_03 [-]: 0.0\nvar_04 [-]: 0.0\nvar_05 [-]: 0.0\nvar_06 [-]: 0.0\nvar_07 [-]: 0.0\nvar_08 [-]: 0.0\nvar_09 [-]: 0.0\nvar_10 [-]: 0.0\nvar_11 [-]: 0.0\nvar_12 [-]: 0.0\nvar_13 [-]: 0.0\nvar_14 [-]: 0.0\nvar_15 [-]: 0.0\nvar_16 [-]: 0.0\n" state = KiteUtils.demo_state_4p(7) @test typeof(state) == SysState{11} @test state.X[end] ≈ 13.62487f0 @@ -45,4 +45,21 @@ using KiteUtils, Test, StructArrays log3 = load_log(dotted_name * ".arrow") # with extension @test log3 isa SysLog @test length(log3.syslog) == 8180 + # verify azimuth_rate round-trips through save_log / load_log + set_data_path(tempdir()) + logger = Logger(7, 3) + for i in 1:3 + ss = KiteUtils.demo_state(7) + ss.azimuth_rate = Float32(i) * 0.1f0 + log!(logger, ss) + end + save_log(logger, "azimuth_rate_test") + rt = load_log("azimuth_rate_test") + @test rt isa SysLog + @test rt.syslog.azimuth_rate ≈ Float32[0.1, 0.2, 0.3] + # verify import_log gracefully skips azimuth_rate when column is absent (old CSV format) + set_data_path("data") + log_csv = import_log("transition") + @test log_csv isa SysLog + @test all(log_csv.syslog.azimuth_rate .== 0.0f0) # absent column → default 0 end \ No newline at end of file