@@ -111,7 +111,7 @@ Create interpolation functions for leading/trailing edges and area.
111111- Tuple of (le_interp, te_interp, area_interp) interpolation functions
112112- Where le_interp and te_interp are tuples themselves, containing the x, y and z interpolations
113113"""
114- function create_interpolations (vertices, circle_center_z, radius, gamma_tip, R; interp_steps= 40 )
114+ function create_interpolations (vertices, circle_center_z, radius, gamma_tip, R= I ( 3 ) ; interp_steps= 40 )
115115 gamma_range = range (- gamma_tip+ 1e-6 , gamma_tip- 1e-6 , interp_steps)
116116 stepsize = gamma_range. step. hi
117117 vz_centered = [v[3 ] - circle_center_z for v in vertices]
@@ -201,7 +201,7 @@ function center_to_com!(vertices, faces)
201201 centroid = (v1 + v2 + v3) / 3
202202
203203 area_total += area
204- com + = area * centroid
204+ com - = area * centroid
205205 else
206206 throw (ArgumentError (" Triangulate faces in a CAD program first" ))
207207 end
@@ -212,7 +212,7 @@ function center_to_com!(vertices, faces)
212212 @info " Centering vertices of .obj file to the center of mass: $com "
213213 com[2 ] = 0.0
214214 for v in vertices
215- v .- = com
215+ v .+ = com
216216 end
217217 return com
218218end
@@ -362,30 +362,29 @@ end
362362
363363
364364"""
365- RamAirWing
366-
367- Represents a curved wing that inherits from Wing with additional geometric properties.
368-
369- # Fields
370- - All fields from Wing:
371- - `n_panels::Int16`: Number of panels in aerodynamic mesh
372- - `n_groups::Int16`: Number of panel groups, each panel group has it's own twisting moment
373- - `spanwise_distribution`::PanelDistribution: see: [PanelDistribution](@ref)
374- - `spanwise_direction::MVec3`: Wing span direction vector
375- - `sections::Vector{Section}`: List of wing sections, see: [Section](@ref)
376- - `refined_sections::Vector{Section}`
377- - `remove_nan::Bool`: Wether to remove the NaNs from interpolations or not
378- - Additional fields:
379- - `circle_center_z::MVec3`: Center of circle coordinates
380- - `gamma_tip::Float64`: Angle between the body frame z axis and the vector going from the kite circular shape center to the wing tip.
381- - `inertia_tensor::Matrix{Float64}`: see: [`calculate_inertia_tensor`](@ref)
382- - `radius::Float64`: Radius of curvature
383- - `le_interp::NTuple{3, Extrapolation}`: see: [Extrapolation](https://juliamath.github.io/Interpolations.jl/stable/extrapolation/)
384- - `te_interp::NTuple{3, Extrapolation}`
385- - `area_interp::Extrapolation`
386- - `theta_dist::Vector{Float64}`
387- - `delta_dist::Vector{Float64}`
388-
365+ RamAirWing <: AbstractWing
366+
367+ A ram-air wing model that represents a curved parafoil with deformable aerodynamic surfaces.
368+
369+ ## Core Features
370+ - Curved wing geometry derived from 3D mesh (.obj file)
371+ - Aerodynamic properties based on 2D airfoil data (.dat file)
372+ - Support for control inputs (twist angles and trailing edge deflections)
373+ - Inertial and geometric properties calculation
374+
375+ ## Notable Fields
376+ - `n_panels::Int16`: Number of panels in aerodynamic mesh
377+ - `n_groups::Int16`: Number of control groups for distributed deformation
378+ - `mass::Float64`: Total wing mass in kg
379+ - `gamma_tip::Float64`: Angular extent from center to wing tip
380+ - `inertia_tensor::Matrix{Float64}`: Full 3x3 inertia tensor in the kite body frame
381+ - `T_cad_body::MVec3`: Translation vector from CAD frame to body frame
382+ - `R_cad_body::MMat3`: Rotation matrix from CAD frame to body frame
383+ - `radius::Float64`: Wing curvature radius
384+ - `theta_dist::Vector{Float64}`: Panel twist angle distribution
385+ - `delta_dist::Vector{Float64}`: Trailing edge deflection distribution
386+
387+ See constructor `RamAirWing(obj_path, dat_path; kwargs...)` for usage details.
389388"""
390389mutable struct RamAirWing <: AbstractWing
391390 n_panels:: Int16
@@ -402,7 +401,8 @@ mutable struct RamAirWing <: AbstractWing
402401 mass:: Float64
403402 gamma_tip:: Float64
404403 inertia_tensor:: Matrix{Float64}
405- center_of_mass:: MVec3
404+ T_cad_body:: MVec3
405+ R_cad_body:: MMat3
406406 radius:: Float64
407407 le_interp:: NTuple{3, Extrapolation}
408408 te_interp:: NTuple{3, Extrapolation}
@@ -413,27 +413,47 @@ mutable struct RamAirWing <: AbstractWing
413413end
414414
415415"""
416- RamAirWing(obj_path, dat_path; alpha=0.0, crease_frac=0.75, wind_vel=10., mass=1.0,
417- n_panels=54, n_sections=n_panels+1, spanwise_distribution=UNCHANGED,
418- spanwise_direction=[0.0, 1.0, 0.0], remove_nan::Bool=true)
419-
420- Constructor for a [RamAirWing](@ref) that allows to use an `.obj` and a `.dat` file as input.
421-
422- # Parameters
423- - obj_path: Path to the `.obj` file used for creating the geometry
424- - dat_path: Path to the `.dat` file, a standard format for 2d foil geometry
425-
426- # Keyword Parameters
427- - crease_frac=0.9: The x coordinate around which the trailing edge rotates on a normalized 2d foil,
428- used in the xfoil polar generation
429- - wind_vel=10.0: Apparent wind speed in m/s, used in the xfoil polar generation
430- - mass=1.0: Mass of the wing in kg, used for the inertia calculations
431- - `n_panels`=56: Number of panels.
432- - `n_sections=n_panels+1`: Number of sections (there is a section on each side of each panel.)
433- - `n_groups=n_panels ÷ 4`: Number of panel groups
434- - `spanwise_distribution`=UNCHANGED: see: [PanelDistribution](@ref)
435- - `spanwise_direction`=[0.0, 1.0, 0.0]
436- - `remove_nan::Bool`: Wether to remove the NaNs from interpolations or not
416+ RamAirWing(obj_path, dat_path; kwargs...)
417+
418+ Create a ram-air wing model from 3D geometry and airfoil data files.
419+
420+ This constructor builds a complete aerodynamic model by:
421+ 1. Loading or generating wing geometry from the .obj file
422+ 2. Creating aerodynamic polars from the airfoil .dat file
423+ 3. Computing inertial properties and coordinate transformations
424+ 4. Setting up control surfaces and panel distribution
425+
426+ # Arguments
427+ - `obj_path`: Path to .obj file containing 3D wing geometry
428+ - `dat_path`: Path to .dat file containing 2D airfoil profile
429+
430+ # Keyword Arguments
431+ - `crease_frac=0.9`: Normalized trailing edge hinge location (0-1)
432+ - `wind_vel=10.0`: Reference wind velocity for XFoil analysis (m/s)
433+ - `mass=1.0`: Wing mass (kg)
434+ - `n_panels=56`: Number of aerodynamic panels across wingspan
435+ - `n_groups=4`: Number of control groups for deformation
436+ - `n_sections=n_panels+1`: Number of spanwise cross-sections
437+ - `align_to_principal=false`: Align body frame to principal axes of inertia
438+ - `spanwise_distribution=UNCHANGED`: Panel distribution type
439+ - `remove_nan=true`: Interpolate NaN values in aerodynamic data
440+ - `alpha_range=deg2rad.(-5:1:20)`: Angle of attack range for polars (rad)
441+ - `delta_range=deg2rad.(-5:1:20)`: Trailing edge deflection range for polars (rad)
442+
443+ # Returns
444+ A fully initialized `RamAirWing` instance ready for aerodynamic simulation.
445+
446+ # Example
447+ ```julia
448+ # Create a ram-air wing from geometry files
449+ wing = RamAirWing(
450+ "path/to/wing.obj",
451+ "path/to/airfoil.dat";
452+ mass=1.5,
453+ n_panels=40,
454+ n_groups=4
455+ )
456+ ```
437457"""
438458function RamAirWing (
439459 obj_path, dat_path;
@@ -458,28 +478,29 @@ function RamAirWing(
458478 if ! ispath (info_path)
459479 @info " Reading $obj_path "
460480 vertices, faces = read_faces (obj_path)
461- center_of_mass = center_to_com! (vertices, faces)
481+ T_cad_body = center_to_com! (vertices, faces)
462482 inertia_tensor = calculate_inertia_tensor (vertices, faces, mass, zeros (3 ))
463483
464484 if align_to_principal
465- inertia_tensor, R_b_p = calc_inertia_y_rotation (inertia_tensor)
466- circle_center_z, radius, gamma_tip = find_circle_center_and_radius (vertices)
467- le_interp, te_interp, area_interp = create_interpolations (vertices, circle_center_z, radius, gamma_tip, R_b_p; interp_steps)
485+ inertia_tensor, R_cad_body = calc_inertia_y_rotation (inertia_tensor)
468486 else
469- circle_center_z, radius, gamma_tip = find_circle_center_and_radius (vertices)
470- le_interp, te_interp, area_interp = create_interpolations (vertices, circle_center_z, radius, gamma_tip, I (3 ); interp_steps)
487+ R_cad_body = I (3 )
471488 end
489+ circle_center_z, radius, gamma_tip = find_circle_center_and_radius (vertices)
490+ le_interp, te_interp, area_interp = create_interpolations (vertices, circle_center_z, radius, gamma_tip, R_cad_body; interp_steps)
472491
473492 @info " Writing $info_path "
474- serialize (info_path, (inertia_tensor, center_of_mass , radius, gamma_tip,
493+ serialize (info_path, (inertia_tensor, T_cad_body, R_cad_body , radius, gamma_tip,
475494 le_interp, te_interp, area_interp))
476495 end
477496
478497 @info " Loading kite info from $info_path and polars from $polar_path "
479498 try
480- (inertia_tensor:: Matrix , center_of_mass :: Vector ,
499+ (inertia_tensor:: Matrix , T_cad_body :: Vector , R_cad_body :: Matrix ,
481500 radius:: Real , gamma_tip:: Real , le_interp, te_interp, area_interp) = deserialize (info_path)
482501
502+ ((R_cad_body == I (3 )) == align_to_principal) && throw (ArgumentError (" Delete $info_path and try again." ))
503+
483504 if ! ispath (polar_path)
484505 width = 2 gamma_tip * radius
485506 area = area_interp (gamma_tip)
@@ -515,7 +536,7 @@ function RamAirWing(
515536
516537 RamAirWing (n_panels, n_groups, spanwise_distribution, panel_props, spanwise_direction, sections,
517538 refined_sections, remove_nan, non_deformed_sections,
518- mass, gamma_tip, inertia_tensor, center_of_mass , radius,
539+ mass, gamma_tip, inertia_tensor, T_cad_body, R_cad_body , radius,
519540 le_interp, te_interp, area_interp, zeros (n_panels), zeros (n_panels), cache)
520541
521542 catch e
0 commit comments