1 | <!DOCTYPE html>
|
2 | <html lang="en">
|
3 | <head>
|
4 | <meta charset="utf-8">
|
5 | <title>math.js | rocket trajectory optimization</title>
|
6 |
|
7 | <script src="../../dist/math.js"></script>
|
8 | <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
|
9 |
|
10 | <style>
|
11 | body {
|
12 | font-family: sans-serif;
|
13 | }
|
14 | </style>
|
15 | </head>
|
16 | <body>
|
17 | <h1>Rocket trajectory optimization</h1>
|
18 | <p>
|
19 | This example simulates the ascent stage of the Apollo Lunar Module modeled using a system of ordinary differential equations.
|
20 | </p>
|
21 |
|
22 | <canvas id=canvas1 width=1600 height=400></canvas>
|
23 | <canvas id=canvas2 width=800 height=400></canvas>
|
24 |
|
25 | <script>
|
26 |
|
27 | function ndsolve(f, x0, dt, tmax) {
|
28 | const n = f.size()[0]
|
29 | const x = x0.clone()
|
30 | const dxdt = []
|
31 | const result = []
|
32 |
|
33 | const nsteps = math.divide(tmax, dt)
|
34 | for(let i=0; i<nsteps; i++) {
|
35 |
|
36 | for(let j=0; j<n; j++) {
|
37 | dxdt[j] = f.get([j]).apply(null, x.toArray())
|
38 | }
|
39 |
|
40 | for(let j=0; j<n; j++) {
|
41 | x.set([j], math.add(x.get([j]), math.multiply(dxdt[j], dt)))
|
42 | }
|
43 | result.push(x.clone())
|
44 | }
|
45 |
|
46 | return math.matrix(result)
|
47 | }
|
48 |
|
49 |
|
50 | math.import({ndsolve:ndsolve})
|
51 |
|
52 |
|
53 |
|
54 | const sim = math.parser()
|
55 |
|
56 | sim.evaluate("G = 6.67408e-11 m^3 kg^-1 s^-2")
|
57 | sim.evaluate("mbody = 5.972e24 kg")
|
58 | sim.evaluate("mu = G * mbody")
|
59 | sim.evaluate("dt = 1.0 s")
|
60 | sim.evaluate("tfinal = 162 s")
|
61 | sim.evaluate("T = 1710000 lbf * 0.9")
|
62 | sim.evaluate("g0 = 9.80665 m/s^2")
|
63 | sim.evaluate("isp = 290 s")
|
64 | sim.evaluate("gamma0 = 89.99883 deg")
|
65 | sim.evaluate("r0 = 6378.1370 km")
|
66 | sim.evaluate("v0 = 10 m/s")
|
67 | sim.evaluate("phi0 = 0 deg")
|
68 | sim.evaluate("m0 = 1207920 lbm + 30000 lbm")
|
69 |
|
70 |
|
71 | sim.evaluate("drdt(r, v, m, phi, gamma) = v sin(gamma)")
|
72 | sim.evaluate("dvdt(r, v, m, phi, gamma) = -mu / r^2 * sin(gamma) + T / m")
|
73 | sim.evaluate("dmdt(r, v, m, phi, gamma) = -T/g0/isp")
|
74 | sim.evaluate("dphidt(r, v, m, phi, gamma) = v/r * cos(gamma) * rad")
|
75 | sim.evaluate("dgammadt(r, v, m, phi, gamma) = (1/r * (v - mu / (r v)) * cos(gamma)) * rad")
|
76 |
|
77 |
|
78 | sim.evaluate("result_stage1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], [r0, v0, m0, phi0, gamma0], dt, tfinal)")
|
79 |
|
80 |
|
81 | sim.evaluate("T = 0 lbf")
|
82 | sim.evaluate("tfinal = 12 s")
|
83 | sim.evaluate("x = flatten(result_stage1[result_stage1.size()[1],:])")
|
84 | sim.evaluate("result_interstage = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
85 |
|
86 | console.log(sim.evaluate("result_interstage[result_interstage.size()[1],3]").toString())
|
87 |
|
88 |
|
89 | sim.evaluate("T = 210000 lbf")
|
90 | sim.evaluate("isp = 348 s")
|
91 | sim.evaluate("tfinal = 397 s")
|
92 | sim.evaluate("x = flatten(result_interstage[result_interstage.size()[1],:])")
|
93 | sim.evaluate("x[3] = 273600 lbm")
|
94 | sim.evaluate("result_stage2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
95 |
|
96 |
|
97 | sim.evaluate("T = 0 lbf")
|
98 | sim.evaluate("tfinal = 60 s")
|
99 | sim.evaluate("x = flatten(result_stage2[result_stage2.size()[1],:])")
|
100 | sim.evaluate("result_unpowered = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | const data_stage1 = sim.evaluate("transpose(concat( transpose( result_stage1[:,4] - phi0) * r0 / rad / km, ( transpose(result_stage1[:,1]) - r0) / km, 1 ))").toArray().map(function(e) { return {x: e[0], y: e[1]} })
|
106 | const data_interstage = sim.evaluate("transpose(concat( transpose(result_interstage[:,4] - phi0) * r0 / rad / km, (transpose(result_interstage[:,1]) - r0) / km, 1 ))").toArray().map(function(e) { return {x: e[0], y: e[1]} })
|
107 | const data_stage2 = sim.evaluate("transpose(concat( transpose( result_stage2[:,4] - phi0) * r0 / rad / km, ( transpose(result_stage2[:,1]) - r0) / km, 1 ))").toArray().map(function(e) { return {x: e[0], y: e[1]} })
|
108 | const data_unpowered = sim.evaluate("transpose(concat( transpose( result_unpowered[:,4] - phi0) * r0 / rad / km, ( transpose(result_unpowered[:,1]) - r0) / km, 1 ))").toArray().map(function(e) { return {x: e[0], y: e[1]} })
|
109 |
|
110 | window['chart'] = new Chart(document.getElementById('canvas1'), {
|
111 | type: 'line',
|
112 | data: {
|
113 | datasets: [{
|
114 | label: "Stage 1",
|
115 | data: data_stage1,
|
116 | fill: false,
|
117 | borderColor: "red",
|
118 | pointRadius: 0
|
119 | }, {
|
120 | label: "Interstage",
|
121 | data: data_interstage,
|
122 | fill: false,
|
123 | borderColor: "green",
|
124 | pointRadius: 0
|
125 | }, {
|
126 | label: "Stage 2",
|
127 | data: data_stage2,
|
128 | fill: false,
|
129 | borderColor: "orange",
|
130 | pointRadius: 0
|
131 | }, {
|
132 | label: "Unpowered",
|
133 | data: data_unpowered,
|
134 | fill: false,
|
135 | borderColor: "blue",
|
136 | pointRadius: 0
|
137 | }]
|
138 | },
|
139 | options: {
|
140 | scales: {
|
141 | xAxes: [{
|
142 | type: 'linear',
|
143 | position: 'bottom'
|
144 | }]
|
145 | }
|
146 | }
|
147 |
|
148 | })
|
149 |
|
150 | </script>
|
151 | </body>
|
152 | </html>
|