Skip to content

Commit 16c8a81

Browse files
authored
Fix moment and force coefficients (#110)
* correct coefficient calculations and add moment coefficient distribution * add tests to check solve * fix com test and throw error on wrong com * fix tests
1 parent 5348677 commit 16c8a81

File tree

4 files changed

+57
-43
lines changed

4 files changed

+57
-43
lines changed

src/kite_geometry.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ function center_to_com!(vertices, faces)
175175
end
176176

177177
com = com / area_total
178-
!(abs(com[2]) < 0.01) && @warn "Center of mass $com has to lie on the xz-plane."
178+
!(abs(com[2]) < 0.01) && throw(ArgumentError("Center of mass $com of .obj file has to lie on the xz-plane."))
179179
@info "Centering vertices of .obj file to the center of mass: $com"
180180
for v in vertices
181181
v .-= com

src/solver.jl

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,24 @@ Struct for storing the solution of the [solve!](@ref) function. Must contain all
77
# Attributes
88
- aero_force::MVec3: Aerodynamic force vector in KB reference frame [N]
99
- aero_moments::MVec3: Aerodynamic moments [Mx, My, Mz] around the reference point [Nm]
10-
- force_coefficients::MVec3: Aerodynamic force coefficients [CL, CD, CS] [-]
10+
- force_coefficients::MVec3: Aerodynamic force coefficients [CFx, CFy, CFz] [-]
11+
- moment_coefficients::MVec3: Aerodynamic moment coefficients [CMx, CMy, CMz] [-]
1112
- moment_distribution::Vector{Float64}: Pitching moments around the spanwise vector of each panel. [Nm]
13+
- moment_coefficient_distribution::Vector{Float64}: Pitching moment coefficient around the spanwise vector of each panel. [-]
1214
- solver_status::SolverStatus: enum, see [SolverStatus](@ref)
1315
"""
1416
mutable struct VSMSolution
1517
aero_force::MVec3
1618
aero_moments::MVec3
1719
force_coefficients::MVec3
20+
moment_coefficients::MVec3
1821
moment_distribution::Vector{Float64}
22+
moment_coefficient_distribution::Vector{Float64}
1923
solver_status::SolverStatus
2024
end
2125

2226
function VSMSolution()
23-
VSMSolution(zeros(MVec3), zeros(MVec3), zeros(MVec3), zeros(3), FAILURE)
27+
VSMSolution(zeros(MVec3), zeros(MVec3), zeros(MVec3), zeros(MVec3), zeros(3), zeros(3), FAILURE)
2428
end
2529

2630
"""
@@ -112,7 +116,9 @@ function solve!(solver::Solver, body_aero::BodyAerodynamics, gamma_distribution=
112116
cm_array = zeros(n_panels)
113117
panel_width_array = zeros(n_panels)
114118
solver.sol.moment_distribution = zeros(n_panels)
119+
solver.sol.moment_coefficient_distribution = zeros(n_panels)
115120
moment_distribution = solver.sol.moment_distribution
121+
moment_coefficient_distribution = solver.sol.moment_coefficient_distribution
116122

117123
# Calculate coefficients for each panel
118124
for (i, panel) in enumerate(panels) # zero bytes
@@ -163,6 +169,9 @@ function solve!(solver::Solver, body_aero::BodyAerodynamics, gamma_distribution=
163169
va = body_aero.va
164170
va_unit = va / va_mag
165171
q_inf = 0.5 * density * va_mag^2
172+
173+
# Calculate wing geometry properties
174+
projected_area = sum(wing -> calculate_projected_area(wing), body_aero.wings)
166175

167176
for (i, panel) in enumerate(panels) # 30625 bytes
168177

@@ -188,25 +197,25 @@ function solve!(solver::Solver, body_aero::BodyAerodynamics, gamma_distribution=
188197
drag_induced_va = drag[i] * dir_drag_induced_va
189198
ftotal_induced_va = lift_induced_va + drag_induced_va
190199

191-
# Calculate forces in prescribed wing frame
192-
dir_lift_prescribed_va = cross(va, spanwise_direction)
193-
dir_lift_prescribed_va = dir_lift_prescribed_va / norm(dir_lift_prescribed_va)
200+
# # Calculate forces in prescribed wing frame
201+
# dir_lift_prescribed_va = cross(va, spanwise_direction)
202+
# dir_lift_prescribed_va = dir_lift_prescribed_va / norm(dir_lift_prescribed_va)
194203

195-
# Calculate force components
196-
lift_prescribed_va = dot(lift_induced_va, dir_lift_prescribed_va) +
197-
dot(drag_induced_va, dir_lift_prescribed_va)
198-
drag_prescribed_va = dot(lift_induced_va, va_unit) +
199-
dot(drag_induced_va, va_unit)
200-
side_prescribed_va = dot(lift_induced_va, spanwise_direction) +
201-
dot(drag_induced_va, spanwise_direction)
204+
# # Calculate force components
205+
# lift_prescribed_va = dot(lift_induced_va, dir_lift_prescribed_va) +
206+
# dot(drag_induced_va, dir_lift_prescribed_va)
207+
# drag_prescribed_va = dot(lift_induced_va, va_unit) +
208+
# dot(drag_induced_va, va_unit)
209+
# side_prescribed_va = dot(lift_induced_va, spanwise_direction) +
210+
# dot(drag_induced_va, spanwise_direction)
202211

203212
# Body frame forces
204213
f_body_3D[:,i] .= ftotal_induced_va .* panel.width
205214

206-
# Update sums
207-
lift_wing_3D_sum += lift_prescribed_va * panel.width
208-
drag_wing_3D_sum += drag_prescribed_va * panel.width
209-
side_wing_3D_sum += side_prescribed_va * panel.width
215+
# # Update sums
216+
# lift_wing_3D_sum += lift_prescribed_va * panel.width
217+
# drag_wing_3D_sum += drag_prescribed_va * panel.width
218+
# side_wing_3D_sum += side_prescribed_va * panel.width
210219

211220
# Calculate the moments
212221
# (1) Panel aerodynamic center in body frame:
@@ -226,26 +235,22 @@ function solve!(solver::Solver, body_aero::BodyAerodynamics, gamma_distribution=
226235
# Calculate the moment distribution (moment on each panel)
227236
arm = (moment_frac - 0.25) * panel.chord
228237
moment_distribution[i] = dot(ftotal_induced_va, panel.z_airf) * arm
238+
moment_coefficient_distribution[i] = moment_distribution[i] ./ (q_inf * projected_area)
229239
end
230240

231-
# Calculate wing geometry properties
232-
projected_area = sum(wing -> calculate_projected_area(wing), body_aero.wings)
233-
234-
Fx = sum(f_body_3D[1,:])
235-
Fy = sum(f_body_3D[2,:])
236-
Fz = sum(f_body_3D[3,:])
237-
Mx = sum(m_body_3D[1,:])
238-
My = sum(m_body_3D[2,:])
239-
Mz = sum(m_body_3D[3,:])
240-
241-
CL = lift_wing_3D_sum / (q_inf * projected_area)
242-
CD = drag_wing_3D_sum / (q_inf * projected_area)
243-
CS = side_wing_3D_sum / (q_inf * projected_area)
244-
245241
# update the result struct
246-
solver.sol.aero_force .= MVec3([Fx, Fy, Fz])
247-
solver.sol.aero_moments .= MVec3([Mx, My, Mz])
248-
solver.sol.force_coefficients .= MVec3([CL, CD, CS])
242+
solver.sol.aero_force .= [
243+
sum(f_body_3D[1,:]),
244+
sum(f_body_3D[2,:]),
245+
sum(f_body_3D[3,:])
246+
]
247+
solver.sol.aero_moments .= [
248+
sum(m_body_3D[1,:]),
249+
sum(m_body_3D[2,:]),
250+
sum(m_body_3D[3,:])
251+
]
252+
solver.sol.force_coefficients .= solver.sol.aero_force ./ (q_inf * projected_area)
253+
solver.sol.moment_coefficients .= solver.sol.aero_moments ./ (q_inf * projected_area)
249254
if converged
250255
# TODO: Check if the result if feasible if converged
251256
solver.sol.solver_status = FEASIBLE

test/test_body_aerodynamics.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,13 @@ end
164164
@test sol.aero_moments.y 0.0 atol=1e-10
165165
@test sol.aero_moments.z -117.97225244011435
166166

167-
@test sol.force_coefficients[1] 0.4920964685099385 # CL
168-
@test sol.force_coefficients[2] 0.0038533739066069946 # CD
169-
@test sol.force_coefficients[3] 0.0 atol=1e-10 # CS
167+
@test sol.force_coefficients[1] -0.039050322560956294 # CFx
168+
@test sol.force_coefficients[2] 0.0 # CFy
169+
@test sol.force_coefficients[3] 0.49055973654418716 # CFz
170+
@test sol.force_coefficients[3] / sol.force_coefficients[1] sol.aero_force[3] / sol.aero_force[1]
170171
@test sol.moment_distribution[1] -0.026242454074087297
172+
@test sol.moment_coefficient_distribution[1] -8.686587525353832e-6
173+
@test sol.moment_distribution[1] / sol.moment_distribution[2] sol.moment_coefficient_distribution[1] / sol.moment_coefficient_distribution[2]
171174

172175
@test sol.solver_status == FEASIBLE
173176

test/test_kite_geometry.jl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ using Serialization
3232
end
3333

3434
@testset "Center of Mass Calculation" begin
35-
vertices = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
35+
vertices = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]
3636
faces = [[1, 2, 3]]
3737

3838
com = center_to_com!(vertices, faces)
39-
expected_com = [1/3, 1/3, 0.0]
39+
expected_com = [1/3, 0.0, 1/3]
4040

4141
@test isapprox(com, expected_com, rtol=1e-5)
4242
end
@@ -75,9 +75,15 @@ using Serialization
7575
@testset "Interpolation Creation" begin
7676
vertices = []
7777
z_center = 2.0
78-
for θ in range(-π/4, π/4, length=10)
79-
push!(vertices, [0.0, r*sin(θ), z_center + r*cos(θ)])
80-
push!(vertices, [1.0, r*sin(θ), z_center + r*cos(θ)])
78+
Δθ = π/2 / 1000
79+
for θ in range(-π/4, π/4-Δθ, 1000)
80+
frac = 1.0 - abs(4θ/π) # Goes from 0 to 1 to 0
81+
x_le = 0.1 - 0.1 * frac # Goes from 0.1 to 0.0 to 0.1
82+
x_te = 0.9 + 0.1 * frac # Goes from 0.9 to 1.0 to 0.9
83+
84+
push!(vertices, [x_le, r*sin(θ), z_center + r*cos(θ)])
85+
push!(vertices, [x_te, r*sin+0.5Δθ), z_center + r*cos+0.5Δθ)])
86+
push!(vertices, [x_le, r*sin+Δθ), z_center + r*cos+Δθ)])
8187
end
8288

8389
# Create test airfoil data file
@@ -108,7 +114,7 @@ using Serialization
108114
serialize(polar_path, (alphas, d_trailing_edge_angles, cl_matrix, cd_matrix, cm_matrix))
109115

110116
# Create and serialize obj file
111-
faces = [[i, i+1, i+2] for i in 1:2:length(vertices)-2]
117+
faces = [[i, i+1, i+2] for i in 1:3:length(vertices)-2]
112118
open(test_obj_path, "w") do io
113119
for v in vertices
114120
println(io, "v $(v[1]) $(v[2]) $(v[3])")

0 commit comments

Comments
 (0)