44#= Model of a kite-power system in implicit form: residual = f(y, yd)
55
66This model implements a 3D mass-spring system with reel-out. It uses six tether segments (the number can be
7- configured in the file data/settings.yaml). The kite is modelled using 4 point masses and 3 aerodynamic
7+ configured in the file data/settings.yaml). The kite is modelled using 4 point masses and 3 aerodynamic
88surfaces. The spring constant and the axial_damping decrease with the segment length. The aerodynamic kite forces
9- are acting on three of the four kite point masses.
9+ are acting on three of the four kite point masses.
1010
1111Four point kite model, included from KiteModels.jl.
1212
@@ -16,7 +16,7 @@ Scientific background: http://arxiv.org/abs/1406.6218 =#
1616# First point, second point, unstressed length.
1717const SPRINGS_INPUT = [0. 1. 150.
1818 1. 2. - 1. # s1, p7, p8
19- 4. 2. - 1. # s2, p10, p8
19+ 4. 2. - 1. # s2, p10, p8
2020 4. 5. - 1. # s3, p10, p11
2121 3. 4. - 1. # s4, p9, p10
2222 5. 1. - 1. # s5, p11, p7
@@ -76,9 +76,9 @@ $(TYPEDFIELDS)
7676 calc_cl:: Spline1D
7777 " Function for calculation the drag coefficient, using a spline based on the provided value pairs."
7878 calc_cd:: Spline1D
79- " wind vector at the height of the kite"
79+ " wind vector at the height of the kite"
8080 v_wind:: T = zeros (S, 3 )
81- " wind vector at reference height"
81+ " wind vector at reference height"
8282 v_wind_gnd:: T = zeros (S, 3 )
8383 " wind vector used for the calculation of the tether drag"
8484 v_wind_tether:: T = zeros (S, 3 )
@@ -97,12 +97,12 @@ $(TYPEDFIELDS)
9797 " max_steering angle in radian"
9898 ks:: S = 0.0
9999 " lift force of the kite; output of calc_aero_forces!"
100- lift_force:: T = zeros (S, 3 )
100+ lift_force:: T = zeros (S, 3 )
101101 " spring force of the current tether segment, output of calc_particle_forces!"
102102 spring_force:: T = zeros (S, 3 )
103103 " last winch force"
104104 last_force:: T = zeros (S, 3 )
105- " a copy of the residual one (pos,vel) for debugging and unit tests"
105+ " a copy of the residual one (pos,vel) for debugging and unit tests"
106106 res1:: SVector{P, KVec3} = zeros (SVector{P, KVec3})
107107 " a copy of the residual two (vel,acc) for debugging and unit tests"
108108 res2:: SVector{P, KVec3} = zeros (SVector{P, KVec3})
@@ -206,7 +206,7 @@ function clear!(s::KPS4)
206206 s. segment_length = s. l_tether / s. set. segments
207207 init_masses! (s)
208208 init_springs! (s)
209- for i in 1 : s. set. segments + KiteModels. KITE_PARTICLES + 1
209+ for i in 1 : s. set. segments + KiteModels. KITE_PARTICLES + 1
210210 s. forces[i] .= zeros (3 )
211211 end
212212 s. drag_force .= [0.0 , 0 , 0 ]
@@ -236,7 +236,7 @@ function clear!(s::KPS4)
236236 s. psi = 0.0
237237 s. rho = s. set. rho_0
238238 s. bridle_factor = s. set. l_bridle / bridle_length (s. set)
239- s. ks = deg2rad (Float64 (s. set. max_steering))
239+ s. ks = deg2rad (Float64 (s. set. max_steering))
240240 s. kcu. depower = s. set. depower:: Float64 / 100.0
241241 s. kcu. set_depower = s. kcu. depower
242242 s. kcu. steering = 0.0
@@ -254,16 +254,28 @@ function clear!(s::KPS4)
254254 KiteModels. set_depower_steering! (s, get_depower (s. kcu), get_steering (s. kcu))
255255end
256256
257+ """
258+ KPS4(kcu::KCU)
259+
260+ Create and initialize a four-point kite power system model from an existing
261+ KCU (kite control unit) instance.
262+
263+ This constructor selects the winch model based on `kcu.set.winch_model`,
264+ creates interpolation splines for lift/drag coefficients, and calls `clear!`
265+ to initialize all state variables.
266+
267+ Returns a `KPS4` instance ready for `init!`/`find_steady_state!` and simulation.
268+ """
257269function KPS4 (kcu:: KCU )
258270 wm = if kcu. set. winch_model == " AsyncMachine"
259271 AsyncMachine (kcu. set)
260272 elseif kcu. set. winch_model == " TorqueControlledMachine"
261273 TorqueControlledMachine (kcu. set)
262274 end
263275 # wm.last_set_speed = kcu.set.v_reel_out
264- s = KPS4 {SimFloat, KVec3, kcu.set.segments+KITE_PARTICLES+1, kcu.set.segments+KITE_SPRINGS, SP} (set= kcu. set,
265- kcu= kcu, wm= wm, calc_cl = Spline1D (kcu. set. alpha_cl, kcu. set. cl_list),
266- calc_cd= Spline1D (kcu. set. alpha_cd, kcu. set. cd_list) )
276+ s = KPS4 {SimFloat, KVec3, kcu.set.segments+KITE_PARTICLES+1, kcu.set.segments+KITE_SPRINGS, SP} (set= kcu. set,
277+ kcu= kcu, wm= wm, calc_cl = Spline1D (kcu. set. alpha_cl, kcu. set. cl_list),
278+ calc_cd= Spline1D (kcu. set. alpha_cd, kcu. set. cd_list) )
267279 clear! (s)
268280 return s
269281end
@@ -272,17 +284,17 @@ function KPS4(set::Settings)
272284 KPS4 (kcu)
273285end
274286
275- """
287+ """
276288 calc_particle_forces!(s::KPS4, pos1, pos2, vel1, vel2, spring, segments, d_tether, rho, i)
277289
278290Calculate the drag force of the tether segment, defined by the parameters pos1, pos2, vel1 and vel2
279291and distribute it equally on the two particles, that are attached to the segment.
280- The result is stored in the array s.forces.
292+ The result is stored in the array s.forces.
281293"""
282294@inline function calc_particle_forces! (s:: KPS4 , pos1, pos2, vel1, vel2, spring, segments, d_tether, rho, i)
283295 l_0 = spring. length # Unstressed length
284296 k = spring. axial_stiffness * s. stiffness_factor # Spring constant
285- c = spring. axial_damping # Damping coefficient
297+ c = spring. axial_damping # Damping coefficient
286298 segment = pos1 - pos2
287299 rel_vel = vel1 - vel2
288300 av_vel = 0.5 * (vel1 + vel2)
@@ -295,7 +307,7 @@ The result is stored in the array s.forces.
295307 spring_vel = unit_vector ⋅ rel_vel
296308 if (norm1 - l_0) > 0.0
297309 if i > segments # kite springs
298- s. spring_force .= (k * (norm1 - l_0) + (c1 * spring_vel)) * unit_vector
310+ s. spring_force .= (k * (norm1 - l_0) + (c1 * spring_vel)) * unit_vector
299311 else
300312 s. spring_force .= (k * (norm1 - l_0) + (c * spring_vel)) * unit_vector
301313 end
@@ -318,7 +330,7 @@ The result is stored in the array s.forces.
318330 end
319331
320332 v_app_perp = s. v_apparent - s. v_apparent ⋅ unit_vector * unit_vector
321- half_drag_force = (- 0.25 * rho * s. set. cd_tether * norm (v_app_perp) * area) * v_app_perp
333+ half_drag_force = (- 0.25 * rho * s. set. cd_tether * norm (v_app_perp) * area) * v_app_perp
322334 if i == segments
323335 v_app_perp_kcu = v_app_kcu - v_app_kcu ⋅ unit_vector * unit_vector
324336 kcu_area = π * (s. set. kcu_diameter/ 2 )^ 2
@@ -355,7 +367,7 @@ Updates the vector s.forces of the first parameter.
355367 pos_B, pos_C, pos_D = pos[s. set. segments+ 3 ], pos[s. set. segments+ 4 ], pos[s. set. segments+ 5 ]
356368 v_A, v_B, v_C, v_D = vel[s. set. segments+ 2 ], vel[s. set. segments+ 3 ], vel[s. set. segments+ 4 ], vel[s. set. segments+ 5 ]
357369 va_1, va_2, va_3, va_4 = s. v_wind - v_A, s. v_wind - v_B, s. v_wind - v_C, s. v_wind - v_D
358-
370+
359371 pos_centre = 0.5 * (pos_C + pos_D)
360372 delta = pos_B - pos_centre
361373 z = - normalize (delta)
448460 loop!(s::KPS4, pos, vel, posd, veld)
449461
450462Calculate the vectors s.res1 and calculate s.res2 using loops
451- that iterate over all tether segments.
463+ that iterate over all tether segments.
452464"""
453465function loop! (s:: KPS4 , pos, vel, posd, veld)
454466 L_0 = s. l_tether / s. set. segments
@@ -462,14 +474,14 @@ function loop!(s::KPS4, pos, vel, posd, veld)
462474 s. res2[1 ] .= vel[1 ]
463475 particles = s. set. segments + KITE_PARTICLES + 1
464476 for i in 2 : particles
465- s. res1[i] .= vel[i] - posd[i]
477+ s. res1[i] .= vel[i] - posd[i]
466478 end
467479 # Compute the masses and forces
468480 m_tether_particle = mass_per_meter * s. segment_length
469481 s. masses[s. set. segments+ 1 ] = s. set. kcu_mass + 0.5 * m_tether_particle
470482 # TODO : check if the next two lines are correct
471483 axial_damping = s. set. axial_damping / L_0
472- axial_stiffness = s. set. axial_stiffness/ L_0
484+ axial_stiffness = s. set. axial_stiffness/ L_0
473485 for i in 1 : s. set. segments
474486 @inbounds s. masses[i] = m_tether_particle
475487 @inbounds s. springs[i] = SP (s. springs[i]. p1, s. springs[i]. p2, s. segment_length, axial_stiffness, axial_damping)
@@ -488,12 +500,12 @@ end
488500 State vector y = pos1, pos2, ... , posn, vel1, vel2, . .., veln, length, v_reel_out
489501 Derivative yd = posd1, posd2, ..., posdn, veld1, veld2, ..., veldn, lengthd, v_reel_outd
490502 Output:
491- Residual res = res1, res2 = vel1-posd1, ..., veld1-acc1, ...,
503+ Residual res = res1, res2 = vel1-posd1, ..., veld1-acc1, ...,
492504
493505 Additional parameters:
494506 s: Struct with work variables, type KPS4
495507 S: The dimension of the state vector
496- The number of the point masses of the model N = S/6, the state of each point
508+ The number of the point masses of the model N = S/6, the state of each point
497509is represented by two 3 element vectors.
498510"""
499511function residual! (res, yd, y:: Vector{SimFloat} , s:: KPS4 , time)
505517function residual! (res, yd, y:: MVector{S, SimFloat} , s:: KPS4 , _) where S
506518 T = S- 2 # T: three times the number of particles excluding the origin
507519 segments = div (T,6 ) - KITE_PARTICLES
508-
520+
509521 # Reset the force vector to zero.
510522 for i in 1 : segments+ KITE_PARTICLES+ 1
511523 s. forces[i] .= SVector (0.0 , 0 , 0 )
@@ -540,9 +552,9 @@ function residual!(res, yd, y::MVector{S, SimFloat}, s::KPS4, _) where S
540552 use_brake = true
541553 end
542554 if s. wm isa AsyncMachine
543- res[end ] = v_reel_outd - calc_acceleration (s. wm:: AsyncMachine , s. sync_speed, v_reel_out, norm (s. forces[1 ]), true )
555+ res[end ] = v_reel_outd - calc_acceleration (s. wm:: AsyncMachine , s. sync_speed, v_reel_out, norm (s. forces[1 ]), true )
544556 elseif ! isnothing (s. wm)
545- res[end ] = v_reel_outd - calc_acceleration (s. wm, v_reel_out, norm (s. forces[1 ]) ; set_speed= s. sync_speed,
557+ res[end ] = v_reel_outd - calc_acceleration (s. wm, v_reel_out, norm (s. forces[1 ]; set_speed= s. sync_speed,
546558 set_torque= s. set_torque, use_brake)
547559 else
548560 res[end ] = v_reel_outd
607619"""
608620 winch_force(s::KPS4)
609621
610- Return the absolute value of the force at the winch as calculated during the last timestep.
622+ Return the absolute value of the force at the winch as calculated during the last timestep.
611623"""
612624function winch_force (s:: KPS4 ) norm (s. last_force) end
613625
@@ -654,13 +666,13 @@ function spring_forces(s::KPS4; prn=true)
654666 pos1, pos2 = s. pos[p1], s. pos[p2]
655667 spring = s. springs[i+ s. set. segments]
656668 l_0 = spring. length # Unstressed length
657- k = spring. axial_stiffness * s. stiffness_factor # Spring constant
669+ k = spring. axial_stiffness * s. stiffness_factor # Spring constant
658670 segment = pos1 - pos2
659671 norm1 = norm (segment)
660672 k1 = 0.25 * k # compression stiffness kite segments
661673 if (norm1 - l_0) > 0.0
662- spring_force = k * (norm1 - l_0)
663- else
674+ spring_force = k * (norm1 - l_0)
675+ else
664676 spring_force = k1 * (norm1 - l_0)
665677 end
666678 forces[i+ s. set. segments] = spring_force
@@ -720,12 +732,12 @@ function find_steady_state!(s::KPS4; prn=false, delta = 0.001, stiffness_factor=
720732 end
721733 # copy the acceleration of point KCU in x direction
722734 i = s. set. segments+ 1
723- F[end - 1 ] = res[1 + 3 * (i- 1 ) + 3 * (s. set. segments+ KITE_PARTICLES)]
735+ F[end - 1 ] = res[1 + 3 * (i- 1 ) + 3 * (s. set. segments+ KITE_PARTICLES)]
724736 # copy the acceleration of point C in y direction
725- i = s. set. segments+ 3
737+ i = s. set. segments+ 3
726738 x = res[1 + 3 * (i- 1 ) + 3 * (s. set. segments+ KITE_PARTICLES)]
727- F[end ] = res[2 + 3 * (i- 1 ) + 3 * (s. set. segments+ KITE_PARTICLES)]
728- return nothing
739+ F[end ] = res[2 + 3 * (i- 1 ) + 3 * (s. set. segments+ KITE_PARTICLES)]
740+ return nothing
729741 end
730742 if prn println (" \n Started function test_nlsolve..." ) end
731743 X00 = zeros (SimFloat, 2 * (s. set. segments+ KITE_PARTICLES- 1 )+ 2 )
@@ -747,7 +759,7 @@ const PRE_STRESS = 0.9998 # Multiplier for the initial spring lengths.
747759# Functions to calculate the initial state vector, the initial masses and initial springs
748760
749761function init_springs! (s:: KPS4 )
750- l_0 = s. set. l_tethers[1 ] / s. set. segments
762+ l_0 = s. set. l_tethers[1 ] / s. set. segments
751763 particles = KiteUtils. get_particles (s. set. height_k, s. set. h_bridle, s. set. width, s. set. m_k)
752764 for j in 1 : size (SPRINGS_INPUT)[1 ]
753765 # build the tether segments
776788function init_masses! (s:: KPS4 )
777789 MASS_FACTOR = 1.0
778790 s. masses = zeros (s. set. segments+ KITE_PARTICLES+ 1 )
779- l_0 = s. set. l_tethers[1 ] / s. set. segments
791+ l_0 = s. set. l_tethers[1 ] / s. set. segments
780792 for i in 1 : s. set. segments
781793 s. masses[i] += 0.5 * l_0 * s. set. rho_tether * (s. set. d_tether/ 2000.0 )^ 2 * pi
782794 s. masses[i+ 1 ] += 0.5 * l_0 * s. set. rho_tether * (s. set. d_tether/ 2000.0 )^ 2 * pi
@@ -789,7 +801,7 @@ function init_masses!(s::KPS4)
789801 s. masses[s. set. segments+ 3 ] += k2 * s. set. mass * MASS_FACTOR
790802 s. masses[s. set. segments+ 4 ] += k3 * s. set. mass * MASS_FACTOR
791803 s. masses[s. set. segments+ 5 ] += k4 * s. set. mass * MASS_FACTOR
792- s. masses
804+ s. masses
793805end
794806
795807function init_pos_vel_acc (s:: KPS4 , X= zeros (2 * (s. set. segments+ KITE_PARTICLES)+ 1 ); old= false , delta = 0.0 )
@@ -810,7 +822,7 @@ function init_pos_vel_acc(s::KPS4, X=zeros(2 * (s.set.segments+KITE_PARTICLES)+1
810822 if old
811823 particles = KiteUtils. get_particles (s. set. height_k, s. set. h_bridle, s. set. width, s. set. m_k)
812824 else
813- particles = KiteUtils. get_particles (s. set. height_k, s. set. h_bridle, s. set. width, s. set. m_k,
825+ particles = KiteUtils. get_particles (s. set. height_k, s. set. h_bridle, s. set. width, s. set. m_k,
814826 pos[s. set. segments+ 1 ], rotate_around_y (vec_c, deg2rad (KITE_ANGLE)), s. v_apparent)
815827 end
816828 j = 1
@@ -836,7 +848,7 @@ function init_pos_vel_acc(s::KPS4, X=zeros(2 * (s.set.segments+KITE_PARTICLES)+1
836848 end
837849 # the velocity vector of the kite particles is the same as the velocity of the last tether point
838850 for i in s. set. segments+ 2 : s. set. segments+ KITE_PARTICLES+ 1
839- vel[i] .+ = vel[s. set. segments+ 1 ]
851+ vel[i] .+ = vel[s. set. segments+ 1 ]
840852 end
841853 pos, vel, acc
842854end
@@ -847,7 +859,7 @@ function set_initial_velocity!(s::KPS4)
847859 end
848860 # the velocity vector of the kite particles is the same as the velocity of the last tether point
849861 for i in s. set. segments+ 2 : s. set. segments+ KITE_PARTICLES+ 1
850- s. vel[i] .= s. vel[s. set. segments+ 1 ]
862+ s. vel[i] .= s. vel[s. set. segments+ 1 ]
851863 end
852864end
853865
0 commit comments