-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsolar_optimization.html
More file actions
378 lines (293 loc) · 16.8 KB
/
solar_optimization.html
File metadata and controls
378 lines (293 loc) · 16.8 KB
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
<!DOCTYPE HTML>
<!--
Arcana by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>Solar UAV Optimization - SUAVE Tutorial</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="https://suave.stanford.edu/assets/css/main.css" />
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-132339206-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-132339206-1');
</script>
</head>
<body class="is-preload">
<div id="page-wrapper">
<!-- Header -->
<div id="header">
<!-- Logo -->
<a hidden id="logo">SUAVE</a>
<!-- Nav -->
<nav id="nav">
<ul>
<li><a href="https://suave.stanford.edu/index.html"> SUAVE</a></li>
<li><a href="https://suave.stanford.edu/download.html">Download</a></li>
<li class="current"><a href="https://suave.stanford.edu/tutorials.html">Tutorials</a></li>
<li><a href="https://suave.stanford.edu/documentation.html">Documentation</a></li>
<li><a href="https://suave.stanford.edu/forum.html">Forum</a></li>
<li><a href="https://suave.stanford.edu/publications.html">Publications</a></li>
<li><a href="https://github.com/suavecode/SUAVE">
<span class="icon2 icon-github">
<img src="https://suave.stanford.edu/images/github_white.svg">
</span>
</a></li>
<li><a href="https://ci.appveyor.com/project/planes/suave">
<span class="icon2 icon-appveyor">
<img src="images/appveyor-logo.svg">
</span>
</a></li>
<li><a href="https://coveralls.io/github/suavecode/SUAVE">
<span class="icon2 icon-coveralls">
<img src="https://suave.stanford.edu/images/coveralls.svg">
</span>
</a></li>
</ul>
</nav>
</div>
<!-- Main -->
<section class="wrapper style1">
<div class="container">
<div id="content">
<!-- Content -->
<article>
<h2 id="solar-uav-optimization-tutorial">Solar UAV Optimization Tutorial</h2>
<p>The purpose of this tutorial is to illustrate a different type of problem. We assume you have gone through the first optimization tutorial: Regional Jet Optimization. This tutorial will illustrate a little more complex setup that modifies a mission parameter.</p>
<p>Your objective is simple: get a small UAV to fly from San Francisco to San Diego. In fact you can pose that as an optimization problem, with some constraints that govern how it works. There is no requirement to minimize this or maximize that. Of course you could try to minimize something, but you just want something that works for now. Later iterations can do fancier things.</p>
<p>Next we will go into detail about some of the required files. <em>Analyses.py</em> and <em>Plot_mission.py</em> are straightforward from prior tutorials. So we will not go into those in detail, except to say that we are using a UAV weight model in <em>Analyses.py</em>.</p>
<h3 id="optimizepy">Optimize.py:</h3>
<p>Let’s pose the optimization problem first and then setup the rest. We start with the <em>Nexus</em> first as usual. With this design problem there are things you are uncertain of and want to solve for.</p>
<p>You’re not sure if you really need any solar panels on the airplane, so to start there will be none. The solar ratio is the ratio of wing area to solar area. A value of 1 would indicate that the entire top of the wing is covered with solar panels.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
# [ tag , initial, [lb,ub], scaling, units ]
problem.inputs = np.array([
[ 'wing_area' , 0.5, ( 0.1, 1.5 ), 0.5, Units.meter ],
[ 'aspect_ratio' , 10.0, ( 5.0, 20.0 ), 10.0, Units.less ],
[ 'dynamic_pressure', 125.0, ( 1.0, 2000.0 ), 125.0, Units.pascals ],
[ 'solar_ratio' , 0.0, ( 0.0, 0.97), 1.0, Units.less ],
[ 'kv' , 800.0, ( 10.0, 10000.0 ), 800.0, Units['rpm/volt']],
])
</code></pre></div></div>
<p>Next come the constraints. The first constraint is that the battery energy can never go negative; the math behind this will be elaborated on later. The next constraint is that the plane must have a battery. Finally there are limits to coefficients of lift and throttle settings.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
# [ tag, sense, edge, scaling, units ]
problem.constraints = np.array([
[ 'energy_constraint', '=', 0.0, 1.0, Units.less],
[ 'battery_mass' , '>', 0.0, 1.0, Units.kg ],
[ 'CL' , '>', 0.0, 1.0, Units.less],
[ 'Throttle_min' , '>', 0.0, 1.0, Units.less],
[ 'Throttle_max' , '>', 0.0, 1.0, Units.less],
])
</code></pre></div></div>
<p>Notice here that all constraints are greater than zero. This is because SciPy’s SLSQP optimization algorithm assumes this form. To correct for these, the values are adjusted in Procedure.py. Other optimization packages such as PyOpt don’t require this strict form.</p>
<p>Finally, the objective. It’s nothing of course! As long as the constraints are met, the goal of the design is satisfied.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
# [ tag, scaling, units ]
problem.objective = np.array([
[ 'Nothing', 1. , Units.kg],
])
</code></pre></div></div>
<h3 id="vehiclespy">Vehicles.py:</h3>
<p>Next, you will setup the vehicle. This is very similar to the prior Solar UAV tutorial, so we will gloss over this. The one noticeable difference is that a lower fidelity energy network is used. This means that most components operate with prescribed efficiencies. For example:</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
# Component 5 the Motor
motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid()
motor.speed_constant = 900. * Units['rpm/volt'] # RPM/volt is standard
motor = size_from_kv(motor)
motor.gear_ratio = 1. # Gear ratio, no gearbox
motor.gearbox_efficiency = 1. # Gear box efficiency, no gearbox
motor.motor_efficiency = 0.8;
net.motor = motor
</code></pre></div></div>
<h3 id="missionspy">Missions.py:</h3>
<p>Now for the mission setup. Here we assume it will take 1000 km and the plane will cruise off the coast at 1000 feet in altitude. The distance is a bit longer than the straight line distance, but we’re not going to fly through populated areas. The heading, or body rotation, must be set to account for the changes in latitude and longitude to accurately calculate the solar radiation. We will cruise at a constant altitude and assume it takes no time to climb and descend compared to the cruise time.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
segment.state.numerics.number_control_points = 50
segment.dynamic_pressure = 115.0 * Units.pascals
segment.start_time = time.strptime("Tue, Jun 21 11:00:00 2020", "%a, %b %d %H:%M:%S %Y",)
segment.altitude = 1000.0 * Units.feet
segment.distance = 1000.0 * Units.km
segment.charge_ratio = 1.0
segment.latitude = 37.4
segment.longitude = -122.15
segment.state.conditions.frames.wind.body_rotations[:,2] = 125.* Units.degrees
</code></pre></div></div>
<h3 id="procedurepy">Procedure.py:</h3>
<p>Finally we have the procedure setup. In the procedure, we resize the vehicle, calculate weights, finalize the analyses, solve the mission, and post process.</p>
<p>Some notes about sizing. Each wing component (main wing, horizontal tail, and vertical tail) needs the surfaces sized based on its area and aspect ratio. Next the solar panels are sized based on the wing area and solar_ratio. Finally the motor is resized based on correlations for the speed constant of the motor.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
def simple_sizing(nexus):
# Pull out the vehicle
vec = nexus.vehicle_configurations.base
# Change the dynamic pressure based on the, add a factor of safety
vec.envelope.maximum_dynamic_pressure = nexus.missions.mission.segments.cruise.dynamic_pressure*1.2
# Scale the horizontal and vertical tails based on the main wing area
vec.wings.horizontal_stabilizer.areas.reference = 0.15 * vec.reference_area
vec.wings.vertical_stabilizer.areas.reference = 0.08 * vec.reference_area
# wing spans,areas, and chords
for wing in vec.wings:
# Unpack
AR = wing.aspect_ratio
S = wing.areas.reference
# Set the spans
wing.spans.projected = np.sqrt(AR*S)
# Set all of the areas for the surfaces
wing.areas.wetted = 2.0 * S
wing.areas.exposed = 1.0 * wing.areas.wetted
wing.areas.affected = 1.0 * wing.areas.wetted
# Set all of the chord lengths
chord = wing.areas.reference/wing.spans.projected
wing.chords.mean_aerodynamic = chord
wing.chords.mean_geometric = chord
wing.chords.root = chord
wing.chords.tip = chord
# Size solar panel area
wing_area = vec.reference_area
spanel = vec.propulsors.network.solar_panel
sratio = spanel.ratio
solar_area = wing_area*sratio
spanel.area = solar_area
spanel.mass_properties.mass = solar_area*(0.60 * Units.kg)
# Resize the motor
motor = vec.propulsors.network.motor
kv = motor.speed_constant
motor = size_from_kv(motor, kv)
# diff the new data
vec.store_diff()
return nexus
</code></pre></div></div>
<p>Here the battery is sized and charged. The battery weight consists of everything that is left over from sizing.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
def weights_battery(nexus):
# Evaluate weights for all of the configurations
config = nexus.analyses.base
config.weights.evaluate()
vec = nexus.vehicle_configurations.base
payload = vec.propulsors.network.payload.mass_properties.mass
msolar = vec.propulsors.network.solar_panel.mass_properties.mass
MTOW = vec.mass_properties.max_takeoff
empty = vec.weight_breakdown.empty
mmotor = vec.propulsors.network.motor.mass_properties.mass
# Calculate battery mass
batmass = MTOW - empty - payload - msolar -mmotor
bat = vec.propulsors.network.battery
initialize_from_mass(bat,batmass)
vec.propulsors.network.battery.mass_properties.mass = batmass
# Set Battery Charge
maxcharge = nexus.vehicle_configurations.base.propulsors.network.battery.max_energy
charge = maxcharge
nexus.missions.mission.segments.cruise.battery_energy = charge
return nexus
</code></pre></div></div>
<p>The next we run the mission and post process the results. The post_process function will setup the information of importance for the user. The energy constraint is a way of ensuring that nowhere in the mission the battery energy goes negative. The coefficient of lift is limited to 1.2. The throttle is limited to 0.9, to make sure there is excess throttle to climb. Throttle is also limited from going negative. Finally, the objective, nothing is specified to be zero.</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
def post_process(nexus):
# Unpack
mis = nexus.missions.mission.segments.cruise
vec = nexus.vehicle_configurations.base
res = nexus.results.mission.segments.cruise.conditions
# Final Energy
maxcharge = vec.propulsors.network.battery.max_energy
# Energy constraints, the battery doesn't go to zero anywhere, using a P norm
p = 8.
energies = res.propulsion.battery_energy[:,0]/np.abs(maxcharge)
energies[energies>0] = 0.0 # Exclude the values greater than zero
energy_constraint = np.sum((np.abs(energies)**p))**(1/p)
# CL max constraint, it is the same throughout the mission
CL = res.aerodynamics.lift_coefficient[0]
# Pack up
summary = nexus.summary
summary.CL = 1.2 - CL
summary.energy_constraint = energy_constraint
summary.throttle_min = res.propulsion.throttle[0]
summary.throttle_max = 0.9 - res.propulsion.throttle[0]
summary.nothing = 0.0
return nexus
</code></pre></div></div>
<h3 id="results">Results</h3>
<p>Let’s look at the results:</p>
<div class="highlight_code"><div class="highlight_code"><pre class="highlight_code"><code>
Optimization terminated successfully (Exit mode 0)
Current function value: 0.0
Iterations: 11
Function evaluations: 87
Gradient evaluations: 11
Design Variable Table:
[['wing_area' 0.5752006084860377 0.1 1.5 0.5 1.0]
['aspect_ratio' 8.565954690253863 5.0 20.0 10.0 1.0]
['dynamic_pressure' 55.97515712027977 1.0 2000.0 125.0 1.0]
['solar_ratio' 0.8312208823908036 0.0 0.97 1.0 1.0]
['kv' 1492.0665786572088 10.0 10000.0 800.0 0.10471975511965977]]
Objective Table:
['Nothing' 0.0 1.0 1.0]
Constraint Table:
[['energy_constraint' 0.0 '=' 0.0 1.0 1]
['battery_mass' 1.5944499541683659 '>' 0.0 1.0 1]
['CL' 0.00866061116778094 '>' 0.0 1.0 1]
['Throttle_min' 0.3067756978833726 '>' 0.0 1.0 1]
['Throttle_max' 0.5932243021166275 '>' 0.0 1.0 1]]
</code></pre></div></div>
<p>Okay looks like SciPy found a feasible solution without too much time. Now let’s review the plots.</p>
<p><img src="/images/Opt_Electronic_Conditions.png" alt="Electronics" width="1000"/></p>
<p>So we can tell now that the battery energy doesn’t go all the way to zero. One thing to note, because we have a solar UAV the voltage is regulated differently and the C-rate doesn't apply in the same way.
Let’s look at how the solar flux varies throughout the day and how that affects the draw from the battery.</p>
<p><img src="/images/Solar_Flux_Power_Energy.png" alt="Solar Flux" width="1000"/></p>
<p>So maybe those solar panels actually are worth it. They seem to decrease the load on the battery considerably during the daytime.</p>
<br>
</article>
</div>
</div>
</section>
<!-- Footer -->
<div id="footer">
<div class="container">
<div class="row">
<section class="col-3 col-6-narrower col-12-mobilep">
<h3>Download</h3>
<ul class="links">
<li><a href="https://suave.stanford.edu/registration.html">Registration</a></li>
<li><a href="https://github.com/suavecode/SUAVE">Github Site</a></li>
</ul>
</section>
<section class="col-3 col-6-narrower col-12-mobilep">
<h3>Learn</h3>
<ul class="links">
<li><a href="https://suave.stanford.edu/tutorials.html">Tutorials</a></li>
<li><a href="https://suave.stanford.edu/documentation.html">Documentation</a></li>
<li><a href="https://suave.stanford.edu/forum.html">Forum</a></li>
</ul>
</section>
<section class="col-3 col-6-narrower col-12-mobilep">
<h3>External Links</h3>
<ul class="links">
<li><a href="http://adl.stanford.edu">Aerospace Design Lab</a></li>
<li><a href="https://aa.stanford.edu">Stanford Aero/Astro</a></li>
<li><a href="https://su2code.github.io">SU2</a></li>
</ul>
</section>
</div>
<!-- Copyright -->
<div class="copyright">
<ul class="menu">
<li>© <script>document.write(new Date().getFullYear())</script> Stanford Aerospace Design Lab <br/>
All rights reserved</li>
</ul>
</div>
</div>
</div>
<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/jquery.dropotron.min.js"></script>
<script src="assets/js/browser.min.js"></script>
<script src="assets/js/breakpoints.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>