|
1 | 1 | # Copyright (c) 2025 Bart van de Lint |
2 | 2 | # SPDX-License-Identifier: MPL-2.0 |
3 | 3 |
|
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 | +=# |
10 | 14 |
|
11 | 15 | using Timers |
12 | 16 | tic() |
13 | 17 | @info "Loading packages " |
14 | 18 |
|
15 | 19 | 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 |
19 | 26 | end |
20 | | -using ControlPlots, LaTeXStrings, ControlSystemsBase |
21 | 27 |
|
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 |
26 | 31 | toc() |
27 | 32 |
|
| 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 | + |
28 | 45 | # Initialize model |
29 | | -set = Settings("system_ram.yaml") |
| 46 | +set = load_settings("system_ram.yaml") |
| 47 | +set.segments = 3 |
30 | 48 | 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" |
31 | 51 |
|
32 | | -@info "Creating SymbolicAWEModel..." |
| 52 | +@info "Creating SymbolicAWEModel model..." |
33 | 53 | s = SymbolicAWEModel(set) |
| 54 | +s.set.abs_tol = 1e-2 |
| 55 | +s.set.rel_tol = 1e-2 |
34 | 56 | toc() |
35 | 57 |
|
36 | 58 | # 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] |
45 | 60 |
|
46 | 61 | # 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 | +) |
48 | 69 | sys = s.sys |
49 | 70 |
|
| 71 | +@show rad2deg(s.integrator[sys.elevation[1]]) |
| 72 | + |
| 73 | + |
50 | 74 | @info "System initialized at:" |
51 | 75 | toc() |
52 | 76 |
|
53 | 77 | # --- Stabilize system at operating point --- |
54 | 78 | @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 |
56 | 85 |
|
57 | 86 | # --- Linearize at operating point --- |
58 | 87 | @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) |
61 | 91 | @info "System linearized with matrix dimensions:" A=size(A) B=size(B) C=size(C) D=size(D) |
62 | 92 |
|
63 | 93 | sys = ss(A,B,C,D) |
|
0 commit comments