Exported Functions
Reading config files
KiteUtils.set_data_path — Function
set_data_path(data_path="")Set the directory for log and config files.
If called without argument, use the data path of the package to obtain the default settings when calling se().
KiteUtils.get_data_path — Function
get_data_path()Get the directory for log and config files.
KiteUtils.load_settings — Function
load_settings(project=PROJECT; relax=false)Reload the global module Settings from the given project file. Returns the updated global settings singleton. To obtain an independent settings instance instead, use the Settings(project) constructor.
The project must include the path and the suffix .yaml .
Parameters
project: The name of the project file to load, defaults to the project that was loaded before.relax: If true, missing sections in the settings file are skipped instead of raising an error.
KiteUtils.update_settings — Function
update_settings()Re-read the settings from a previously loaded project. Returns the new settings.
KiteUtils.copy_settings — Function
copy_settings()Copy the default settings.yaml and system.yaml files to the folder DATAPATH (it will be created if it doesn't exist).
KiteUtils.copy_examples — Function
copy_examples()Copy all example scripts to the folder "examples" (it will be created if it doesn't exist).
KiteUtils.se — Function
se(project=PROJECT; relax=false)Getter function for the Settings struct.
The settings.yaml file to load is determined by the content active PROJECT, which defaults to system.yaml. The project file must be located in the directory specified by the data path get_data_path.
se(settings::Settings, project=PROJECT; relax=false)Update function for the Settings struct.
The settings.yaml file to load is determined by the content active PROJECT, which defaults to system.yaml. The project file must be located in the directory specified by the data path get_data_path.
KiteUtils.se_dict — Function
se_dict()Getter function for the dictionary, representing the settings.yaml file.
Access to the dict is much slower than access to the setting struct, but more flexible.
Usage example: z0 = se_dict()["environment"]["z0"]
KiteUtils.sync_wind! — Function
sync_wind!(set::Settings)Synchronise the wind representation in set. If use_wind_vec is true, compute v_wind, upwind_dir and upwind_elevation from wind_vec. Otherwise compute wind_vec from the three scalars.
Angles in Settings are stored in degrees; the conversion functions operate in radians, so this function handles the conversion.
KiteUtils.check_wind_input — Function
check_wind_input(set::Settings, sym::Symbol)Throw an ArgumentError if sym is a wind field that sync_wind! derives rather than reads, so that writing it would be lost. use_wind_vec decides which fields those are; every other sym is accepted.
KiteUtils.wc_settings — Function
wc_settings(project=PROJECT)Get the winch controller (WC) settings filename from the project file.
Returns the filename specified in the wc_settings field of the system section. The project file defaults to the currently active PROJECT.
KiteUtils.fpc_settings — Function
fpc_settings(project=PROJECT)Get the flight path controller (FPC) settings filename from the project file.
Returns the filename specified in the fpc_settings field of the system section. The project file defaults to the currently active PROJECT.
KiteUtils.fpp_settings — Function
fpp_settings(project=PROJECT)Get the flight path planner (FPP) settings filename from the project file.
Returns the filename specified in the fpp_settings field of the system section. The project file defaults to the currently active PROJECT.
KiteUtils.vsm_settings_file — Function
vsm_settings_file(project=PROJECT)Get the vortex step model (VSM) settings filename from the project file.
Returns the filename specified in the vsm_settings field of the system section. The project file defaults to the currently active PROJECT.
KiteUtils.aero_geometry_file — Function
aero_geometry_file(project=PROJECT)Get the aerodynamic geometry filename from the project file.
Returns the filename specified in the aero_geometry field of the system section. The project file defaults to the currently active PROJECT.
KiteUtils.structural_geometry_file — Function
structural_geometry_file(project=PROJECT)Get the structural geometry filename from the project file.
Returns the filename specified in the structural_geometry field of the system section. Falls back to struc_geometry for compatibility. The project file defaults to the currently active PROJECT.
Also look at the default example: settings.yaml .
Modify .yaml files
KiteUtils.readfile — Function
readfile(filename)Read the lines of a text file.
KiteUtils.writefile — Function
writefile(lines, filename)Write the lines to a file.
KiteUtils.change_value — Function
change_value(lines, varname, value::Union{Integer, Float64})Change the value of a variable in a yaml file for a number.
change_value(lines, varname, value::String)Change the value of a variable in a yaml file.
KiteUtils.update_yaml_scalar — Function
update_yaml_scalar(lines, key, value) -> (lines, updated)Replace the value of the first line whose stripped form starts with key, keeping the original indentation and trailing comment. key includes the colon, e.g. "v_wind:". updated is false if no such line exists; use insert_yaml_scalar_in_section to add the key in that case.
Unlike change_value, the replacement is not padded to the width of the old value, and the caller learns whether anything was changed.
KiteUtils.insert_yaml_scalar_in_section — Function
insert_yaml_scalar_in_section(lines, section, key, value) -> (lines, true)Insert key value into section, indented like the section's existing children. Both section and key include the colon, e.g. "gui:" and "default_turbulence:". The section itself is appended if it is not present at all, so the second return value is always true.
KiteUtils.get_comment — Function
get_comment(lines, key)Get the comment of a variable in a yaml file.
KiteUtils.get_unit — Function
get_unit(lines, key)Get the unit of a variable in a yaml file. The unit must be defined in square brackets.
Wings and bodies of a state
KiteUtils.wing_Q — Function
wing_Q(state, k)The quaternion of wing k, Q[k]: a mutable view into a SysState, or the time series of a SysLog's syslog.
KiteUtils.body_Q — Function
body_Q(state, b)The quaternion of body b, Q[K + b] behind the K wings, as wing_Q does.
KiteUtils.wing_pos — Function
wing_pos(state, k)The position of wing k, the k-th of the last O position slots: a mutable view into a SysState, or the time series of a SysLog's syslog.
KiteUtils.body_pos — Function
body_pos(state, b)The position of body b, the slot behind the K wings' in the last O, as wing_pos does.
Creating test data
KiteUtils.demo_state — Function
demo_state(P, height=6.0, time=0.0; azimuth_north=-pi/2, counts...)Create a demo state with a given height and time. P is the number of tether particles and counts the other keywords of SysState(P; ...); the entries they add are zero. Kite is parking and aligned with the tether.
Returns a SysState instance.
KiteUtils.demo_state_4p — Function
demo_state_4p(P, height=6.0, time=0.0; azimuth_north=-pi/2)Create a demo state, using the 4 point kite model with a given height and time. P is the number of tether particles.
Returns a SysState instance.
KiteUtils.demo_syslog — Function
demo_syslog(P, O=1, D=0, L=0, W=1, T=W, S=0, N=0; wings=1, duration=10)Create a demo flight log with given duration [s] as StructArray of SysState{P, O, K, D, L, W, T, S, N, MyFloat} with K = wings, the counts meaning what they mean there. The demo data fills the points and frame 1; every other entry is zero.
KiteUtils.demo_log — Function
demo_log(P, name="Test_flight"; duration=10)Create an artificial SysLog struct for demonstration purposes. P is the number of tether particles.
KiteUtils.get_particles — Function
get_particles(height_k, height_b, width, m_k, pos_pod= [ 75., 0., 129.90381057], vec_c=[-15., 0., -25.98076211],
v_app=[10.4855, 0, -3.08324])Calculate the initial positions of the particles representing a 4-point kite, connected to a kite control unit (KCU).
Parameters:
- height_k: height of the kite itself, not above ground [m]
- height_b: height of the bridle [m]
- width: width of the kite [m]
- mk: relative nose distance
- pos_pod: position of the control pod
- vec_c: vector of the last tether segment
Loading, saving and converting log files
KiteUtils.log! — Function
log!(logger::Logger, state::SysState)Log a state in a logger object. Do nothing if the preallocated size would be exceeded. Returns the current number of elements of the log.
KiteUtils.load_log — Function
load_log(filename::String; path="", frame=nothing)Read a log file that was saved as .arrow file. Everything the returned SysLog holds is KA: the orientations and every body-resolved column alike, and the table metadata the file carries comes back as its metadata field.
Logs written by KiteUtils 0.13 and later declare their convention and are read by it. An older log declares nothing and is KS, that being what the format specified, so that is how it is read, with a warning saying so.
frame states what an undeclared log actually holds and silences that warning. It is the escape hatch for a log that did not honour the specification: SymbolicAWEModels wrote Q_b_to_w into the field unconverted, so its logs of that era hold KA already and need load_log(name; frame=KA), or their orientations come back upside down. Passing frame=KS confirms the specified convention for a log known to honour it. A log that declares a convention is taken at its word and frame is not consulted.
KiteUtils.save_log — Function
save_log(logger::Logger, name="sim_log", compress=true; path="",
colmeta=default_colmeta(),
metadata::Dict{String, String}=Dict{String, String}())Save the rows that were logged as .arrow file. Compression is lz4 unless compress is passed as false. metadata is written as the table metadata of the file, beside the creation time of the logger under the key created, and read back by load_log. It is opaque to KiteUtils; the keys log_metadata writes are merged over it, so a log always declares the frame convention it is in.
arrow-js does not implement IPC body decompression, so a log written with the default lz4 compression cannot be read in a browser.
save_log(flight_log::SysLog, compress=true; path="",
metadata::Dict{String, String}=flight_log.metadata)Save a flight log of type SysLog as .arrow file. Compression is lz4 unless compress is passed as false. metadata is written as the table metadata of the file and read back by load_log, and defaults to the metadata the log already carries. It is opaque to KiteUtils; the keys log_metadata writes are merged over it, so a log always declares the frame convention it is in.
arrow-js does not implement IPC body decompression, so a log written with the default lz4 compression cannot be read in a browser.
KiteUtils.import_log — Function
import_log(filename; frame=KA)Read a .csv file with a flight log and return a SysLog object. Everything the returned SysLog holds is KA, as after load_log.
A .csv carries no metadata, so unlike an .arrow it cannot say which convention it was written in and nothing can be inferred from its age. frame states it: a .csv that export_log wrote from a loaded log holds KA and is the default; one exported before KiteUtils 0.13 holds KS and needs frame=KS.
Parameters:
- filename: name of the file without extension.
KiteUtils.export_log — Function
export_log(flight_log; path="")Save a flight log of type SysLog as .csv file.
KiteUtils.default_colmeta — Function
default_colmeta()The column metadata of a log whose caller named none: each of the free columns var_01 to var_16 displayed under its own name.
KiteUtils.sys_log — Function
sys_log(logger::Logger, name="sim_log"; colmeta=default_colmeta(),
metadata::Dict{String, String}=Dict{String, String}())Convert the data of a Logger into a SysLog, holding the rows that were logged, the name of the log and the column meta data. The table metadata of the SysLog is metadata plus the creation time of the logger under the key created.
KiteUtils.syslog — Function
syslog(logger::Logger)The rows that were logged, as a StructArray of SysState. It is a view on the columns of logger, so the steps it has room for but never logged are left out and the logger stays usable.
Base.getproperty — Function
Base.getproperty(log::SysLog, sym::Symbol)Implement the properties x, y and z. They represent the kite position for the 4-point kite model. In addition, implements the properties x1, y1 and z1. They represent the kite position for the 1-point model.
The function set_data_path(data_path) can be used to set the directory for the log files.
Frame conventions
Convert an orientation between the two body-frame conventions, KS and KA. A vector resolved in the body frame is not an orientation and takes fromKS2KA_body; a world vector takes fromENU2NED or fromNED2ENU.
KiteUtils.fromKS2KA — Function
fromKS2KA(rot::AbstractMatrix)
fromKS2KA(q::QuatRotation)
fromKS2KA(q::AbstractVector)Convert an orientation from the KS convention to the KA convention. The orientation is the rotation from the body frame to the world frame: its columns are the body axes expressed in the world frame.
Both the world frame and the body frame change, so converting an orientation rotates each of them, where a body vector needs only the body frame rotated and takes fromKS2KA_body, and a world vector only the world frame and takes fromENU2NED. The orientation may be given as a QuatRotation, as a rotation matrix or as a 4-element vector [w, i, j, k], and comes back in the same form: a QuatRotation, an SMatrix{3, 3} or an SVector{4}.
KiteUtils.fromKA2KS — Function
fromKA2KS(orientation)Convert an orientation from the KA convention to the KS convention. The conversion is an involution, so this is fromKS2KA.
KiteUtils.fromKS2KA_body — Function
fromKS2KA_body(v::AbstractVector)Convert a vector resolved in the body frame — a force, a moment, a turn rate — from KS components to KA components. Only the body frame turns, so this rotates on one side where an orientation rotates on both and takes fromKS2KA, and a world vector turns with the world frame and takes fromENU2NED. The rotation is a half turn about the shared spanwise axis, so y survives and x and z change sign.
The conversion is an involution, so fromKA2KS_body is this function.
KiteUtils.fromKA2KS_body — Function
fromKA2KS_body(v::AbstractVector)Convert a vector resolved in the body frame from KA components to KS components. The conversion is an involution, so this is fromKS2KA_body.
KiteUtils.orient_matrix — Function
orient_matrix(attitude)Rotation matrix of the kite in the KA convention, whatever form attitude arrives in: a quaternion (QuatRotation or [w, i, j, k]), a rotation matrix, or roll, pitch and yaw angles as a 3-element vector. Everything but the Euler angles is already KA; Euler angles are KS, that being the only convention they are reported in, and are converted.
KiteUtils.euler_KS — Function
euler_KS(attitude)Roll, pitch and yaw angles in radian of a kite whose attitude is given in the KA convention. The angles themselves are KS: they are measured against NED, because that is what the sensors report and what flight test data is compared against.
KiteUtils.log_metadata — Function
log_metadata()Table-level metadata written into every .arrow log, recording the frame convention its orientations and body-resolved columns are in. Without it a log cannot be told apart from one written before KiteUtils 0.13, which is KS.
KiteUtils.log_convention — Function
log_convention(table)Frame convention an Arrow log declares, or nothing when it declares none. Only logs written by KiteUtils 0.13 and later carry a declaration, so nothing means the log is older and its convention has to be assumed.
A declaration this version does not recognise is an error rather than a nothing: assuming a convention for it would silently mirror every orientation in the log.
KiteUtils.fromKS2KA_columns! — Function
fromKS2KA_columns!(Qw, Qx, Qy, Qz)Convert every orientation in a log's quaternion columns from KS to KA in place, one per timestep and oriented frame. The columns must be mutable; Arrow columns are not.
KiteUtils.fromKS2KA_body_columns! — Function
fromKS2KA_body_columns!(x, y, z)Convert every body vector in a log's per-body component columns — turn_rate_x/y/z, say — from KS to KA in place with fromKS2KA_body, one per timestep and oriented frame. The columns must be mutable; Arrow columns are not.
Rotation matrices and conversions
KiteUtils.calc_orient_rot — Function
calc_orient_rot(x, y, z; viewer=false, ENU=true)Calculate the rotation matrix based on the kite reference frame, by default passed as ENU (east, north, up), or as NED (north, east, down) if ENU is false. If viewer is true, the rotation matrix is calculated based with respect to the viewer reference frame.
The axes and the result are KS; pass the result through fromKS2KA to obtain the KA orientation stored in SysState. For KA axes given in ENU the orientation is simply [x y z], no function needed.
KiteUtils.fromENU2NED — Function
fromENU2NED(vec::AbstractVector)Convert a vector from ENU (east, north, up) to NED (north, east, down) reference frame.
KiteUtils.fromNED2ENU — Function
fromNED2ENU(vec::AbstractVector)Convert a vector from NED (north, east, down) to ENU (east, north, up) reference frame.
KiteUtils.is_right_handed_orthonormal — Function
is_right_handed_orthonormal(x, y, z)Returns true if the vectors x, y and z form a right-handed orthonormal basis.
KiteUtils.quat2euler — Function
quat2euler(q::QuatRotation)
quat2euler(q::AbstractVector)Convert a quaternion to roll, pitch, and yaw angles in radian. The quaternion can be a 4-element vector (w, i, j, k) or a QuatRotation object.
KiteUtils.quat2viewer — Function
quat2viewer(attitude)Convert a KA orientation to the viewer reference frame. See orient_matrix for the accepted forms of attitude. Returns a quaternion as a 4-element vector [w,i,j,k].
KiteUtils.euler2rot — Function
euler2rot(roll, pitch, yaw)Calculate the rotation matrix based on the roll, pitch, and yaw angles in radian.
KiteUtils.rot3d — Method
rot3d(ax, ay, az, bx, by, bz)Calculate the rotation matrix that needs to be applied on the reference frame (ax, ay, az) to match the reference frame (bx, by, bz). All parameters must be 3-element vectors. Both reference frames must be orthogonal, all vectors must already be normalized.
Source: TRIAD_Algorithm
KiteUtils.rot — Method
rot(pos_kite, pos_before, v_app)Calculate the rotation matrix of the kite based on the position of the last two tether particles and the apparent wind speed vector. Assumption: The kite aligns with the apparent wind direction. If used for the model KPS4, pass the vector -x of the kite reference frame instead of v_app.
Coordinate system transformations
KiteUtils.fromENU2EG — Function
fromENU2EG(pointENU)Transform the position of the kite in the ENU (east, north, up) reference frame to the Earth Groundstation (north, west, up) reference frame.
KiteUtils.fromEG2W — Function
fromEG2W(vector, down_wind_direction = pi/2.0)Transform a vector (x,y,z) from Earth Groundstation to Wind reference frame.
KiteUtils.fromW2SE — Function
fromW2SE(vector, elevation, azimuth)Transform a (velocity-) vector (x,y,z) from Wind to Small Earth reference frame .
KiteUtils.fromKS2EX — Function
fromKS2EX(vector, orientation)Transform a vector (x,y,z) from KiteSensor to Earth Xsens reference frame.
Sensor ingest only: everything downstream of the sensor works in KA and ENU.
- orientation in Euler angles (roll, pitch, yaw)
KiteUtils.fromEX2EG — Function
fromEX2EG(vector)Transform a vector (x,y,z) from EarthXsens to Earth Groundstation reference frame.
Sensor ingest only: everything downstream of the sensor works in KA and ENU.
Wind vector conversions
KiteUtils.wind_vec_from_angles — Function
wind_vec_from_angles(v_wind, upwind_dir, upwind_elevation)Compute the wind vector in the ENU reference frame from wind speed, upwind direction and upwind elevation. All angles in radians.
v_wind: wind speed [m/s]upwind_dir: direction the wind is coming from, zero at north, clockwise positive [rad]upwind_elevation: angle of the upwind direction above the east-north plane [rad]
Returns an SVec3 (east, north, up).
KiteUtils.angles_from_wind_vec — Function
angles_from_wind_vec(wind_vec)Compute wind speed, upwind direction and upwind elevation from a wind vector in the ENU reference frame.
Returns (v_wind, upwind_dir, upwind_elevation), all angles in radians. upwind_dir is zero at north, clockwise positive, in the range -π .. π. upwind_elevation is the angle of the upwind direction above the east-north plane.
Geometric calculations
Calculate the elevation angle, the azimuth angle and the ground distance based on the kite position. In addition, calculate the heading angle, the heading vector, the asin and acos (safe versions) and the initial kite reference frame.
KiteUtils.calc_elevation — Function
calc_elevation(vec)Calculate the elevation angle in radian from the kite position.
KiteUtils.calc_heading — Function
calc_heading(attitude, elevation, azimuth; upwind_dir=-pi/2, respos=true)Calculate the heading angle of the kite in radians. The heading is the direction the nose of the kite is pointing to, expressed in the Small Earth (SE) reference frame.
Arguments
attitude: Orientation of the kite as aKAquaternion or rotation matrix, or as Euler angles (roll, pitch, yaw) in radian, which areKS(measured against NED)elevation: Elevation angle of the kite in radiansazimuth: Azimuth angle of the kite in radiansupwind_dir: Direction the wind is coming from in radians; zero at north; clockwise positive from above (default: -π/2, wind from west)respos: If true, return angle in range [0, 2π]; if false, return in range [-π, π] (default: true)
Returns
The heading angle in radians, measured from the positive x-axis of the SE reference frame.
KiteUtils.calc_course — Function
calc_course(velocityENU, elevation, azimuth, down_wind_direction = π/2, respos=true)Calculate the course angle in radian.
- velocityENU: Kite velocity in EastNorthUp reference frame
- downwinddirection: The direction the wind is going to; zero at north; clockwise positive from above; default: going to east.
- respos: If true, the result is in the range 0 .. 2π, otherwise -π .. π
KiteUtils.calc_heading_w — Function
calc_heading_w(attitude, down_wind_direction = pi/2.0)Calculate the heading vector in wind reference frame from a KA attitude. See orient_matrix for the accepted forms of attitude.
KiteUtils.azimuth_east — Function
azimuth_east(vec)Calculate the azimuth angle in radian from the kite position in ENU reference frame. Zero east. Positive direction clockwise seen from above. Valid range: -π .. π.
KiteUtils.azimuth_north — Function
azimuth_north(vec)Calculate the azimuth angle in radian from the kite position in ENU reference frame. Zero north. Positive direction anti-clockwise seen from above. Valid range: -π .. π.
KiteUtils.azn2azw — Function
azn2azw(azimuth_north; upwind_dir = -π/2)Calculate the azimuth in the wind reference frame. The upwind_dir is the direction the wind is coming from Zero is at north; clockwise positive. Default: Wind from west.
Returns:
- Angle in radians. Zero straight downwind. Positive direction clockwise seen from above.
- Valid range: -pi .. pi.
KiteUtils.ground_dist — Function
ground_dist(vec)Calculate the ground distance of the kite from the groundstation based on the kite position (x,y,z, z up).
KiteUtils.acos2 — Function
acos2(arg)Calculate the acos of arg, but allow values slightly above one and below minus one to avoid exceptions in case of rounding errors. Returns an angle in radian.
KiteUtils.asin2 — Function
asin2(arg)Calculate the asin of arg, but allow values slightly above one and below minus one to avoid exceptions in case of rounding errors. Returns an angle in radian.
KiteUtils.wrap2pi — Function
wrap2pi(angle)Limit the angle to the range -π .. π .
KiteUtils.initial_kite_ref_frame — Function
initial_kite_ref_frame(vec_c, v_app)Calculate the initial orientation of the kite based on the last tether segment and the apparent wind speed.
Parameters:
vec_c: (pos_n-2) - (pos_n-1) n: number of particles without the three kite particles that do not belong to the main tether (P1, P2 and P3).v_app: vector of the apparent wind speed
Returns: x, y, z: the unit vectors of the kite reference frame in the ENU reference frame
Physical calculations
KiteUtils.calculate_rotational_inertia — Function
calculate_rotational_inertia(X::Vector, Y::Vector, Z::Vector, M::Vector,
around_center_of_mass::Bool=true, rotation_point::Vector=[0, 0, 0])Calculate the rotational inertia (Ixx, Ixy, Ixz, Iyy, Iyz, Izz) of a collection of point masses around a point. By default this point is the center of mass which will be calculated, but any point can be given to rotation_point.
Parameters:
- X: x-coordinates of the point masses.
- Y: y-coordinates of the point masses.
- Z: z-coordinates of the point masses.
- M: masses of the point masses.
around_center_of_mass: Calculate the rotational inertia around the center of mass?rotation_point: Rotation point used if not rotating around the center of mass.
Returns: The tuple Ixx, Ixy, Ixz, Iyy, Iyz, Izz where:
- Ixx: rotational inertia around the x-axis.
- Ixy: rotational inertia around the xy-plane.
- Ixz: rotational inertia around the xz-plane.
- Iyy: rotational inertia around the y-axis.
- Iyz: rotational inertia around the yz-plane.
- Izz: rotational inertia around the z-axis.