/
wing.py
202 lines (166 loc) · 6.14 KB
/
wing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
" wing.py "
from builtins import range
from os import sep
from os.path import abspath, dirname
import numpy as np
import pandas as pd
from gpkit import Model, parse_variables
from .wing_core import WingCore
from .wing_skin import WingSkin
from .capspar import CapSpar
from gpfit.fit_constraintset import XfoilFit
#pylint: disable=no-member, invalid-name, unused-argument, exec-used
#pylint: disable=undefined-variable, attribute-defined-outside-init
#pylint: disable=too-many-instance-attributes
class Planform(Model):
""" Planform Area Definition
Scalar Variables
---------
S [ft^2] surface area
AR [-] aspect ratio
b [ft] span
tau [-] airfoil thickness ratio
CLmax 1.39 [-] maximum lift coefficient
CM 0.14 [-] wing moment coefficient
croot [ft] root chord
cmac [ft] mean aerodynamic chord
lam 0.5 [-] taper ratio
cbarmac self.return_cmac [-] non-dim MAC
Variables of length N
---------------------
eta np.linspace(0,1,N) [-] (2y/b)
cbar self.return_c [-] non-dim chord at nodes
Variables of length N-1
-----------------------
cave [ft] mid section chord
cbave self.return_avg [-] non-dim mid section chord
deta self.return_deta [-] \\Delta (2y/b)
Upper Unbounded
--------------- # bounding any pair of variables will work
cave, b, tau
Lower Unbounded
---------------
cave, b, tau
LaTex Strings
-------------
tau \\tau
CLmax C_{L_{\\mathrm{max}}}
CM C_M
croot c_{\\mathrm{root}}
cmac c_{\\mathrm{MAC}}
lam \\lambda
cbarmac \\bar{c}_{\\mathrm{MAC}}
"""
def return_c(self, c):
" return normalized chord distribution "
lam = c(self.lam).to("dimensionless").magnitude
eta = c(self.eta).to("dimensionless").magnitude
return np.array([2./(1+lam)*(1+(lam-1)*e) for e in eta])
def return_cmac(self, c):
" return normalized MAC "
cbar = self.return_c(c)
lam = cbar[1:]/cbar[:-1]
maci = 2./3*cbar[:-1]*(1 + lam + lam**2)/(1 + lam)
deta = np.diff(c(self.eta))
num = sum([(cbar[i] + cbar[i+1])/2*maci[i]*deta[i] for i
in range(len(deta))])
den = sum([(cbar[i] + cbar[i+1])/2*deta[i] for i in range(len(deta))])
return num/den/cbar[0]
return_avg = lambda self, c: (self.return_c(c)[:-1]
+ self.return_c(c)[1:])/2.
return_deta = lambda self, c: np.diff(c(self.eta))
def setup(self, N):
exec(parse_variables(Planform.__doc__))
return [b**2 == S*AR,
cave == cbave*S/b,
croot == S/b*cbar[0],
cmac == croot*cbarmac]
class WingAero(Model):
""" Wing Aero Model
Variables
---------
Cd [-] wing drag coefficient
CL [-] lift coefficient
CLstall 1.3 [-] stall CL
e 0.9 [-] span efficiency
Re [-] reynolds number
cdp [-] wing profile drag coefficient
Upper Unbounded
---------------
Cd, Re, static.planform.AR
state.V, state.mu (if not muValue), state.rho (if not rhoValue)
Lower Unbounded
---------------
state.V, state.mu (if not muValue), state.rho (if not rhoValue)
LaTex Strings
-------------
Cd C_d
CL C_L
CLstall C_{L_{\\mathrm{stall}}}
cdp c_{d_p}
"""
def setup(self, static, state,
fitdata=dirname(abspath(__file__)) + sep + "jho_fitdata.csv"):
self.state = state
self.static = static
exec(parse_variables(WingAero.__doc__))
df = pd.read_csv(fitdata)
fd = df.to_dict(orient="records")[0]
AR = static.planform.AR
cmac = static.planform.cmac
rho = state.rho
V = state.V
mu = state.mu
# needed for Climb model in solar
self.rhoValue = bool(rho.key.value)
self.muValue = bool(mu.key.value)
if fd["d"] == 2:
independentvars = [CL, Re]
elif fd["d"] == 3:
independentvars = [CL, Re, static.planform.tau]
return [Cd >= cdp + CL**2/np.pi/AR/e,
Re == rho*V*cmac/mu,
# XfoilFit(fd, cdp, [CL, Re], airfoil="jho1.dat"),
XfoilFit(fd, cdp, independentvars, name="polar"),
CL <= CLstall
]
class Wing(Model):
"""
Wing Model
Variables
---------
W [lbf] wing weight
mfac 1.2 [-] wing weight margin factor
SKIP VERIFICATION
Upper Unbounded
---------------
W, planform.tau (if not sparJ)
Lower Unbounded
---------------
planform.b, spar.Sy (if sparModel), spar.J (if sparJ)
LaTex Strings
-------------
mfac m_{\\mathrm{fac}}
"""
sparModel = CapSpar
fillModel = WingCore
flight_model = WingAero
skinModel = WingSkin
sparJ = False
def setup(self, N=5):
self.N = N
exec(parse_variables(Wing.__doc__))
self.planform = Planform(N)
self.components = []
if self.skinModel:
self.skin = self.skinModel(self.planform)
self.components.extend([self.skin])
if self.sparModel:
self.spar = self.sparModel(N, self.planform)
self.components.extend([self.spar])
self.sparJ = hasattr(self.spar, "J")
if self.fillModel:
self.foam = self.fillModel(self.planform)
self.components.extend([self.foam])
constraints = [W/mfac >= sum(c["W"] for c in self.components)]
return constraints, self.planform, self.components