Skip to content

Commit 8c22c13

Browse files
committed
Revert "Remove SymbolicAWEModel code from the package (#247)"
This reverts commit 0e5fb65.
1 parent 8c122b1 commit 8c22c13

32 files changed

+3611
-152
lines changed

Project.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
2727
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
2828
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
2929
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
30+
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
3031
Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc"
3132
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
3233
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
@@ -35,7 +36,6 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
3536
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
3637
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
3738
Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4"
38-
SymbolicAWEModels = "9c9a347c-5289-41db-a9b9-25ccc76c3360"
3939
SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5"
4040
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
4141
Timers = "21f18d07-b854-4dab-86f0-c15a3821819a"
@@ -70,7 +70,7 @@ KiteUtils = "0.10.15"
7070
LaTeXStrings = "1.4.0"
7171
LinearAlgebra = "1.10, 1.11"
7272
LinearSolve = "~2.39.0, 3"
73-
ModelingToolkit = "10.10.0"
73+
ModelingToolkit = "~9.78.0"
7474
NLSolversBase = "~7.8.3"
7575
NLsolve = "4.5"
7676
NonlinearSolve = "4.8.0"
@@ -82,6 +82,7 @@ Parameters = "0.12"
8282
Pkg = "1.10, 1.11"
8383
PrecompileTools = "1.2, 1.3"
8484
REPL = "1.10.0, 1.11.0"
85+
Reexport = "1.1, 1.2"
8586
Rotations = "1.7"
8687
SHA = "0.7.0"
8788
SciMLBase = "<2.115"
@@ -90,12 +91,11 @@ StaticArrays = "1.9.7"
9091
Statistics = "1"
9192
StatsBase = "0.34"
9293
Sundials = "4.24"
93-
SymbolicAWEModels = "0.1.2"
9494
SymbolicIndexingInterface = "0.3"
9595
SymbolicUtils = "3.25"
9696
Test = "1"
9797
Timers = "0.1.5"
98-
VortexStepMethod = "2.0.0"
98+
VortexStepMethod = "1.2.6"
9999
WinchModels = "0.3.6"
100100
julia = "1.10, 1.11"
101101

data/settings_ram.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ system:
33
# use / as path delimiter, even on Windows
44
time_lapse: 1.0 # relative replay speed
55
sim_time: 100.0 # simulation time [sim only]
6-
segments: 3 # number of tether segments
6+
segments: 6 # number of tether segments
77
sample_freq: 20 # sample frequency in Hz
88
zoom: 0.03 # zoom factor for the system view
99
kite_scale: 3.0 # relative zoom factor for the 4 point kite
1010
fixed_font: "" # name or filepath+filename of alternative fixed pitch font
1111

1212
initial:
13-
l_tethers: [50.0, 50.4, 50.4] # initial tether length [m]
13+
l_tethers: [50.0, 50.0, 50.0] # initial tether length [m]
1414
elevation: 70.8 # initial elevation angle [deg]
1515
v_reel_outs: [0.0, 0.0, 0.0] # initial reel out speed [m/s]
1616

@@ -69,7 +69,7 @@ environment:
6969
rho_0: 1.225 # air density at zero height and 15 °C [kg/m³]
7070
alpha: 0.08163 # exponent of the wind profile law
7171
z0: 0.0002 # surface roughness [m]
72-
profile_law: 3 # 1=EXP, 2=LOG, 3=EXPLOG
72+
profile_law: 3 # 1=EXP, 2=LOG, 3=EXPLOG, 4=F
7373
# the following parameters are for calculating the turbulent wind field using the Mann model
7474
use_turbulence: 0.0 # turbulence intensity relative to Cabau, NL
7575
v_wind_gnds: [3.483, 5.324, 8.163] # wind speeds at ref height for calculating the turbulent wind field [m/s]

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ makedocs(;
2828
"Home" => "index.md",
2929
"Types" => "types.md",
3030
"Functions" => "functions.md",
31+
"SymbolicAWEModel" => "ram_air_kite.md",
3132
"Parameters" => "parameters.md",
3233
"Examples 1p" => "examples.md",
3334
"Examples 4p" => "examples_4p.md",

docs/src/functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set_v_wind_ground!
3434
unstretched_length
3535
tether_length
3636
pos_kite
37+
calc_aoa
3738
calc_height
3839
calc_elevation
3940
calc_azimuth

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ times faster.
8383
- the documentation was improved
8484

8585
## Provides
86-
The types [`KPS3`](@ref), [`KPS4`](@ref) and `SymbolicAWEModel`, representing the one point, the four point kite model and the ram air kite model, together with the high level simulation interface consisting of the functions [`init!`](@ref) and [`next_step!`](@ref). Other kite models can be added inside or outside of this package by implementing the non-generic methods required for an AbstractKiteModel.
86+
The types [`KPS3`](@ref), [`KPS4`](@ref) and [`SymbolicAWEModel`](@ref), representing the one point, the four point kite model and the ram air kite model, together with the high level simulation interface consisting of the functions [`init!`](@ref) and [`next_step!`](@ref). Other kite models can be added inside or outside of this package by implementing the non-generic methods required for an AbstractKiteModel.
8787

8888
Additional functions to provide inputs and outputs of the model on each time step. In particular the constructor [`SysState`](@ref) can be called once per time step to create a SysState struct for
8989
logging or for displaying the state in a viewer. For the KPS3 and KPS4 model, once per time step the [`residual!`](@ref) function is called as many times as needed to find the solution at the end

docs/src/ram_air_kite.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
```@meta
2+
CurrentModule = KiteModels
3+
```
4+
## Introduction
5+
The [`SystemStructure`](@ref) provides a flexible framework for defining the physical structure of airborne wind energy (AWE) systems using discrete mass-spring-damper models. This structure can represent many different AWE system configurations, from simple single-line kites to complex multi-wing systems with intricate bridle networks.
6+
7+
The [`SystemStructure`](@ref) serves as input to the [`SymbolicAWEModel`](@ref), which is based on ModelingToolkit and automatically generates symbolic differential algebraic equations from the structural definition.
8+
9+
## Workflow
10+
1. Define system components ([`Point`](@ref), [`Segment`](@ref), [`Group`](@ref), etc.)
11+
2. Assemble into a [`SystemStructure`](@ref)
12+
3. Pass to [`SymbolicAWEModel`](@ref) for automatic MTK model generation
13+
4. Simulate the resulting symbolic model
14+
15+
## Public enumerations
16+
```@docs
17+
SegmentType
18+
DynamicsType
19+
```
20+
21+
## Public constructors
22+
```@docs
23+
SystemStructure(name, set; points=Point[], groups=Group[], segments=Segment[],
24+
pulleys=Pulley[], tethers=Tether[], winches=Winch[],
25+
wings=Wing[], transforms=Transform[])
26+
SystemStructure
27+
SymbolicAWEModel(::Settings, ::SystemStructure, ::Vector{<:BodyAerodynamics}, ::Vector{<:VortexStepMethod.Solver})
28+
SymbolicAWEModel(::Settings)
29+
Point(idx, pos_cad, type)
30+
Point
31+
Group(::Any, ::Any, ::RamAirWing, ::Any, ::Any, ::Any)
32+
Group
33+
Segment(idx, point_idxs, type)
34+
Segment
35+
Pulley(idx, segment_idxs, type)
36+
Pulley
37+
Tether
38+
Winch(idx, model, tether_idxs, tether_length; tether_vel=0.0)
39+
Winch
40+
Wing(idx, group_idxs, R_b_c, pos_cad)
41+
Wing
42+
Transform(idx, elevation, azimuth, heading)
43+
Transform
44+
```
45+
46+
## Private functions
47+
```@docs
48+
wing_eqs!
49+
reinit!
50+
scalar_eqs!
51+
linear_vsm_eqs!
52+
force_eqs!
53+
```

docs/src/tutorial_system_structure.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ segments = Segment[]
3535
points = push!(points, Point(1, zeros(3), STATIC; wing_idx=0))
3636
```
3737

38-
The first point we add is a static point. There are four different `DynamicsType`s to choose from: `STATIC`, `QUASI_STATIC`, `DYNAMIC` and `WING`. `STATIC` just means that the point doesn't move. `DYNAMIC` is a point modeled with acceleration, while `QUASI_STATIC` constrains this acceleration to be zero at all times. A `WING` point is connected to a wing body.
38+
The first point we add is a static point. There are four different [`DynamicsType`](@ref)s to choose from: `STATIC`, `QUASI_STATIC`, `DYNAMIC` and `WING`. `STATIC` just means that the point doesn't move. `DYNAMIC` is a point modeled with acceleration, while `QUASI_STATIC` constrains this acceleration to be zero at all times. A `WING` point is connected to a wing body.
3939

4040
Now we can add `DYNAMIC` points and connect them to each other with segments. `BRIDLE` segments don't need to have a tether, because they have a constant unstretched length.
4141
```julia
@@ -51,21 +51,21 @@ for i in 1:set.segments
5151
end
5252
```
5353

54-
In order to describe the initial orientation of the structure, we define a `Transform` with an elevation (-80 degrees), azimuth and heading, and a base position `[0.0, 0.0, 50.0]`.
54+
In order to describe the initial orientation of the structure, we define a [`Transform(idx, elevation, azimuth, heading)`](@ref) with an elevation (-80 degrees), azimuth and heading, and a base position `[0.0, 0.0, 50.0]`.
5555
```julia
5656
transforms = [Transform(1, deg2rad(-80), 0.0, 0.0;
5757
base_pos = [0.0, 0.0, 50.0], base_point_idx=points[1].idx,
5858
rot_point_idx=points[end].idx)]
5959
```
6060

61-
From the points, segments and transform we create a `SystemStructure`, which can be plotted in 2d to quickly investigate if the model is correct.
61+
From the points, segments and transform we create a [`SystemStructure(name, set)`](@ref), which can be plotted in 2d to quickly investigate if the model is correct.
6262
```julia
6363
sys_struct = SystemStructure("tether", set; points, segments, transforms)
6464
plot(sys_struct, 0.0)
6565
```
6666
![SystemStructure visualization](tether_sys_struct.png)
6767

68-
If the system looks good, we can easily model it, by first creating a `SymbolicAWEModel`, initializing it and stepping through time.
68+
If the system looks good, we can easily model it, by first creating a [`SymbolicAWEModel`](@ref), initializing it and stepping through time.
6969
```julia
7070
sam = SymbolicAWEModel(set, sys_struct)
7171

docs/src/types.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ AKM
1616
```@docs
1717
KPS3
1818
KPS4
19+
SymbolicAWEModel
1920
```
2021
These structs store the state of the one point model and four point model. Only in unit tests
2122
it is allowed to access the members directly, otherwise use the input and output functions.

examples/lin_ram_model.jl

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,93 @@
11
# Copyright (c) 2025 Bart van de Lint
22
# SPDX-License-Identifier: MPL-2.0
33

4-
# This example demonstrates how to:
5-
# - Load a system configuration from a YAML file,
6-
# - Initialize a SymbolicAWEModel with specified winch torques,
7-
# - Stabilize the system at its operating point,
8-
# - Linearize the system at that point,
9-
# - And plot the Bode plots of the resulting linearized system.
4+
#=
5+
This example demonstrates linearized model accuracy by comparing:
6+
1. Nonlinear SymbolicAWEModel model simulation
7+
2. Linearized state-space model simulation
8+
9+
Both models start from the same operating point and are subjected
10+
to identical steering inputs. The resulting state trajectories are
11+
plotted together to visualize how well the linearized model
12+
approximates the nonlinear dynamics.
13+
=#
1014

1115
using Timers
1216
tic()
1317
@info "Loading packages "
1418

1519
PLOT = true
16-
using Pkg
17-
if ! ("LaTeXStrings" keys(Pkg.project().dependencies))
18-
using TestEnv; TestEnv.activate()
20+
if PLOT
21+
using Pkg
22+
if ! ("LaTeXStrings" keys(Pkg.project().dependencies))
23+
using TestEnv; TestEnv.activate()
24+
end
25+
using ControlPlots, LaTeXStrings, ControlSystemsBase
1926
end
20-
using ControlPlots, LaTeXStrings, ControlSystemsBase
2127

22-
using KiteModels, KiteUtils, LinearAlgebra, Statistics
23-
using KiteModels.SymbolicAWEModels: find_steady_state!
24-
using KiteModels.SymbolicAWEModels.ModelingToolkit
25-
using KiteModels.SymbolicAWEModels.ModelingToolkit: t_nounits
28+
using KiteModels, LinearAlgebra, Statistics, OrdinaryDiffEqCore
29+
using ModelingToolkit
30+
using ModelingToolkit: t_nounits
2631
toc()
2732

33+
# TODO: use sparse autodiff
34+
35+
# Simulation parameters
36+
dt = 0.001
37+
total_time = 1.0 # Increased from 0.1s to 1.0s for better dynamics observation
38+
vsm_interval = 3
39+
steps = Int(round(total_time / dt))
40+
41+
# Steering parameters
42+
steering_freq = 1/2 # Hz - full left-right cycle frequency
43+
steering_magnitude = 5.0 # Magnitude of steering input [Nm]
44+
2845
# Initialize model
29-
set = Settings("system_ram.yaml")
46+
set = load_settings("system_ram.yaml")
47+
set.segments = 3
3048
set_values = [-50.0, 0.0, 0.0] # Set values of the torques of the three winches. [Nm]
49+
set.quasi_static = false
50+
set.physical_model = "simple_ram"
3151

32-
@info "Creating SymbolicAWEModel..."
52+
@info "Creating SymbolicAWEModel model..."
3353
s = SymbolicAWEModel(set)
54+
s.set.abs_tol = 1e-2
55+
s.set.rel_tol = 1e-2
3456
toc()
3557

3658
# Define outputs for linearization - heading
37-
@variables begin
38-
heading(t_nounits)[1]
39-
angle_of_attack(t_nounits)[1]
40-
tether_len(t_nounits)[1:3]
41-
winch_force(t_nounits)[1:3]
42-
end
43-
lin_outputs = [heading[1], angle_of_attack[1], tether_len[1], winch_force[1]]
44-
@info "Linear outputs: $lin_outputs"
59+
lin_outputs = @variables heading(t_nounits)[1]
4560

4661
# Initialize at elevation with linearization outputs
47-
init!(s; lin_outputs)
62+
s.sys_struct.winches[2].tether_length += 0.2
63+
s.sys_struct.winches[3].tether_length += 0.2
64+
KiteModels.init!(s;
65+
remake=false,
66+
reload=true,
67+
lin_outputs # Specify which outputs to track in linear model
68+
)
4869
sys = s.sys
4970

71+
@show rad2deg(s.integrator[sys.elevation[1]])
72+
73+
5074
@info "System initialized at:"
5175
toc()
5276

5377
# --- Stabilize system at operating point ---
5478
@info "Stabilizing system at operating point..."
55-
find_steady_state!(s)
79+
s.integrator.ps[sys.stabilize] = true
80+
stabilization_steps = Int(10 ÷ dt)
81+
for i in 1:stabilization_steps
82+
next_step!(s; dt, vsm_interval=0.05÷dt)
83+
end
84+
s.integrator.ps[sys.stabilize] = false
5685

5786
# --- Linearize at operating point ---
5887
@info "Linearizing system at operating point..."
59-
(; A, B, C, D) = linearize!(s)
60-
@time (; A, B, C, D) = linearize!(s)
88+
@time (; A, B, C, D) = KiteModels.linearize(s)
89+
@time (; A, B, C, D) = KiteModels.linearize(s)
90+
@show norm(A)
6191
@info "System linearized with matrix dimensions:" A=size(A) B=size(B) C=size(C) D=size(D)
6292

6393
sys = ss(A,B,C,D)

examples/menu.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ options = ["bench = include(\"bench.jl\")",
1818
"steering_test_4p = include(\"steering_test_4p.jl\")",
1919
"ram_air_kite = SIMPLE=false; include(\"ram_air_kite.jl\")",
2020
"simple_ram_air_kite = SIMPLE=true; include(\"ram_air_kite.jl\")",
21+
"lin_ram_model = include(\"lin_ram_model.jl\")",
2122
"calc_spectrum = include(\"calc_spectrum.jl\")",
2223
"plot_spectrum_ = include(\"plot_spectrum.jl\")",
2324
"calculate_rotational_inertia = include(\"calculate_rotational_inertia.jl\")",
@@ -38,4 +39,4 @@ function example_menu()
3839
end
3940
end
4041

41-
example_menu()
42+
example_menu()

0 commit comments

Comments
 (0)