mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-25 15:07:57 +00:00
Publish v9.0.0
This commit is contained in:
parent
85572fa57e
commit
188c7240fa
@ -295,23 +295,35 @@ math.evaluate('0o77') // 63
|
||||
math.evaluate('0xff') // 255
|
||||
```
|
||||
|
||||
Non-decimal literals are parsed as 32 bit signed integers:
|
||||
A word size suffix can be used to change the behavior of non decimal literal evaluation:
|
||||
|
||||
```js
|
||||
math.evaluate('0xffffffff') // -1
|
||||
math.evaluate('0xfffffffff') // SyntaxError: String "0xfffffffff" is out of range
|
||||
math.evaluate('0xffi8') // -1
|
||||
math.evaluate('0xffffffffi32') // -1
|
||||
math.evaluate('0xfffffffffi32') // SyntaxError: String "0xfffffffff" is out of range
|
||||
```
|
||||
|
||||
Numbers can be formatted as binary, octal, and hex strings using the functions
|
||||
`bin`, `oct`, and `hex`:
|
||||
Numbers can be formatted as binary, octal, and hex strings using the `notation` option of the `format` function:
|
||||
|
||||
```js
|
||||
math.evaluate('bin(3)') // '0b11'
|
||||
math.evaluate('oct(63)') // '0o77'
|
||||
math.evaluate('hex(255)') // '0xff'
|
||||
math.evaluate('hex(-1)') // '0xffffffff'
|
||||
math.evaluate('hex(2.3)') // Error: Value must be an integer
|
||||
math.evaluate('hex(2^35)') // Error: Value must be in range [-2^31, 2^31-1]
|
||||
math.evaluate('format(3, {notation: "bin"})') // '0b11'
|
||||
math.evaluate('format(63, {notation: "oct"})') // '0o77'
|
||||
math.evaluate('format(255, {notation: "hex"})') // '0xff'
|
||||
math.evaluate('format(-1, {notation: "hex"})') // '-0x1'
|
||||
math.evaluate('format(2.3, {notation: "hex"})') // '0x2.4cccccccccccc'
|
||||
```
|
||||
|
||||
The `format` function accepts a `wordSize` option to use in conjunction with the non binary notations:
|
||||
|
||||
```js
|
||||
math.evaluate('format(-1, {notation: "hex", wordSize: 8})') // '0xffi8'
|
||||
```
|
||||
|
||||
The functions `bin`, `oct`, and `hex` are shorthand for the `format` function with `notation` set accordingly:
|
||||
|
||||
```js
|
||||
math.evaluate('bin(-1)') // '-0b1'
|
||||
math.evaluate('bin(-1, 8)') // '0b11111111i8'
|
||||
```
|
||||
|
||||
<h3 id="bignumbers">BigNumbers <a href="#bignumbers" title="Permalink">#</a></h3>
|
||||
|
||||
@ -20,6 +20,7 @@ math.bin(value)
|
||||
Parameter | Type | Description
|
||||
--------- | ---- | -----------
|
||||
`value` | number | Value to be stringified
|
||||
`wordSize` | number | Optional word size (see `format`)
|
||||
|
||||
<h3 id="returns">Returns <a href="#returns" title="Permalink">#</a></h3>
|
||||
|
||||
|
||||
@ -41,6 +41,17 @@ math.format(value, callback)
|
||||
`lower` and `upper` bounds, and uses exponential notation elsewhere.
|
||||
Lower bound is included, upper bound is excluded.
|
||||
For example '123.4' and '1.4e7'.
|
||||
- 'bin', 'oct, or 'hex'
|
||||
Format the number using binary, octal, or hexadecimal notation.
|
||||
For example '0b1101' and '0x10fe'.
|
||||
- `wordSize: number`
|
||||
The word size in bits to use for formatting in binary, octal, or
|
||||
hexadecimal notation. To be used only with 'bin', 'oct', or 'hex'
|
||||
values for 'notation' option. When this option is defined the value
|
||||
is formatted as a signed twos complement integer of the given word
|
||||
size and the size suffix is appended to the output.
|
||||
For example format(-1, {notation: 'hex', wordSize: 8}) === '0xffi8'.
|
||||
Default value is undefined.
|
||||
- `precision: number`
|
||||
A number between 0 and 16 to round the digits of the number. In case
|
||||
of notations 'exponential', 'engineering', and 'auto', `precision`
|
||||
|
||||
@ -20,6 +20,7 @@ math.hex(value)
|
||||
Parameter | Type | Description
|
||||
--------- | ---- | -----------
|
||||
`value` | number | Value to be stringified
|
||||
`wordSize` | number | Optional word size (see `format`)
|
||||
|
||||
<h3 id="returns">Returns <a href="#returns" title="Permalink">#</a></h3>
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ math.oct(value)
|
||||
Parameter | Type | Description
|
||||
--------- | ---- | -----------
|
||||
`value` | number | Value to be stringified
|
||||
`wordSize` | number | Optional word size (see `format`)
|
||||
|
||||
<h3 id="returns">Returns <a href="#returns" title="Permalink">#</a></h3>
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ Math.js can be downloaded or linked from various content delivery networks:
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>unpkg</td>
|
||||
<td><a href="https://unpkg.com/mathjs@8.1.1/">https://unpkg.com/mathjs@8.1.1/</a></td>
|
||||
<td><a href="https://unpkg.com/mathjs@9.0.0/">https://unpkg.com/mathjs@9.0.0/</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>cdnjs</td>
|
||||
@ -49,8 +49,8 @@ Math.js can be downloaded or linked from various content delivery networks:
|
||||
Or download the full bundle directly from [unpkg](https://unpkg.com):
|
||||
|
||||
<p>
|
||||
<a href="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js">
|
||||
math.js (version 8.1.1, <span id="size">141 kB</span>, minified and gzipped)
|
||||
<a href="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js">
|
||||
math.js (version 9.0.0, <span id="size">141 kB</span>, minified and gzipped)
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ File: [angle_configuration.html](angle_configuration.html) (click for a live dem
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | basic usage</title>
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ File: [basic_usage.html](basic_usage.html) (click for a live demo)
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | basic usage</title>
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | currency conversion</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
|
||||
<style>
|
||||
body,
|
||||
|
||||
@ -13,7 +13,7 @@ File: [currency_conversion.html](currency_conversion.html) (click for a live dem
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | currency conversion</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
|
||||
<style>
|
||||
body,
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ File: [custom_separators.html](custom_separators.html) (click for a live demo)
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | plot</title>
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
|
||||
<script src="https://cdn.plot.ly/plotly-1.35.2.min.js"></script>
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ File: [plot.html](plot.html) (click for a live demo)
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | plot</title>
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
|
||||
<script src="https://cdn.plot.ly/plotly-1.35.2.min.js"></script>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | pretty printing with MathJax</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ File: [pretty_printing_with_mathjax.html](pretty_printing_with_mathjax.html) (cl
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | pretty printing with MathJax</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | printing HTML</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
|
||||
@ -13,7 +13,7 @@ File: [printing_html.html](printing_html.html) (click for a live demo)
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | printing HTML</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
<script>
|
||||
// load math.js using require.js
|
||||
require(['https://unpkg.com/mathjs@8.1.1/lib/browser/math.js'], function (math) {
|
||||
require(['https://unpkg.com/mathjs@9.0.0/lib/browser/math.js'], function (math) {
|
||||
// evaluate some expression
|
||||
const result = math.evaluate('1.2 * (2 + 4.5)')
|
||||
document.write(result)
|
||||
|
||||
@ -18,7 +18,7 @@ File: [requirejs_loading.html](requirejs_loading.html) (click for a live demo)
|
||||
|
||||
<script>
|
||||
// load math.js using require.js
|
||||
require(['https://unpkg.com/mathjs@8.1.1/lib/browser/math.js'], function (math) {
|
||||
require(['https://unpkg.com/mathjs@9.0.0/lib/browser/math.js'], function (math) {
|
||||
// evaluate some expression
|
||||
const result = math.evaluate('1.2 * (2 + 4.5)')
|
||||
document.write(result)
|
||||
|
||||
@ -1,152 +1,301 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | rocket trajectory optimization</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#canvas-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 5%;
|
||||
margin-top: 5%;
|
||||
}
|
||||
|
||||
#canvas-grid>div {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Rocket trajectory optimization</h1>
|
||||
<p>
|
||||
This example simulates the ascent stage of the Apollo Lunar Module modeled using a system of ordinary differential equations.
|
||||
This example simulates the launch of a SpaceX Falcon 9 modeled using a system of ordinary differential equations.
|
||||
</p>
|
||||
|
||||
<canvas id=canvas1 width=1600 height=400></canvas>
|
||||
<canvas id=canvas2 width=800 height=400></canvas>
|
||||
<canvas id="canvas" width="1600" height="600"></canvas>
|
||||
<div id="canvas-grid"></div>
|
||||
|
||||
<script>
|
||||
|
||||
// Solve ODE `dx/dt = f(x,t), x(0) = x0` numerically.
|
||||
function ndsolve(f, x0, dt, tmax) {
|
||||
const n = f.size()[0] // Number of variables
|
||||
const x = x0.clone() // Current values of variables
|
||||
const dxdt = [] // Temporary variable to hold time-derivatives
|
||||
const result = [] // Contains entire solution
|
||||
|
||||
let x = x0.clone() // Current values of variables
|
||||
const result = [x] // Contains entire solution
|
||||
const nsteps = math.divide(tmax, dt) // Number of time steps
|
||||
for(let i=0; i<nsteps; i++) {
|
||||
for (let i = 0; i < nsteps; i++) {
|
||||
// Compute derivatives
|
||||
for(let j=0; j<n; j++) {
|
||||
dxdt[j] = f.get([j]).apply(null, x.toArray())
|
||||
}
|
||||
const dxdt = f.map(func => func(...x.toArray()))
|
||||
// Euler method to compute next time step
|
||||
for(let j=0; j<n; j++) {
|
||||
x.set([j], math.add(x.get([j]), math.multiply(dxdt[j], dt)))
|
||||
}
|
||||
result.push(x.clone())
|
||||
const dx = math.multiply(dxdt, dt)
|
||||
x = math.add(x, dx)
|
||||
result.push(x)
|
||||
}
|
||||
|
||||
return math.matrix(result)
|
||||
}
|
||||
|
||||
// Import the numerical ODE solver
|
||||
math.import({ndsolve:ndsolve})
|
||||
math.import({ ndsolve })
|
||||
|
||||
// Create a math.js context for our simulation. Everything else occurs in the context of the expression parser!
|
||||
|
||||
const sim = math.parser()
|
||||
|
||||
sim.evaluate("G = 6.67408e-11 m^3 kg^-1 s^-2") // Gravitational constant
|
||||
sim.evaluate("mbody = 5.972e24 kg") // Mass of Earth
|
||||
sim.evaluate("mu = G * mbody")
|
||||
sim.evaluate("dt = 1.0 s") // Simulation timestep
|
||||
sim.evaluate("tfinal = 162 s") // Simulation duration
|
||||
sim.evaluate("T = 1710000 lbf * 0.9") // Engine thrust
|
||||
sim.evaluate("mbody = 5.9724e24 kg") // Mass of Earth
|
||||
sim.evaluate("mu = G * mbody") // Standard gravitational parameter
|
||||
sim.evaluate("g0 = 9.80665 m/s^2") // Standard gravity: used for calculating prop consumption (dmdt)
|
||||
sim.evaluate("isp = 290 s") // Specific impulse
|
||||
sim.evaluate("gamma0 = 89.99883 deg") // Initial pitch angle (90 deg is vertical)
|
||||
sim.evaluate("r0 = 6378.1370 km") // Equatorial radius of Earth
|
||||
sim.evaluate("v0 = 10 m/s") // Initial velocity (must be non-zero because ODE is ill-conditioned)
|
||||
sim.evaluate("r0 = 6371 km") // Mean radius of Earth
|
||||
sim.evaluate("t0 = 0 s") // Simulation start
|
||||
sim.evaluate("dt = 0.5 s") // Simulation timestep
|
||||
sim.evaluate("tfinal = 149.5 s") // Simulation duration
|
||||
sim.evaluate("isp_sea = 282 s") // Specific impulse (at sea level)
|
||||
sim.evaluate("isp_vac = 311 s") // Specific impulse (in vacuum)
|
||||
sim.evaluate("gamma0 = 89.99970 deg") // Initial pitch angle (90 deg is vertical)
|
||||
sim.evaluate("v0 = 1 m/s") // Initial velocity (must be non-zero because ODE is ill-conditioned)
|
||||
sim.evaluate("phi0 = 0 deg") // Initial orbital reference angle
|
||||
sim.evaluate("m0 = 1207920 lbm + 30000 lbm") // Initial mass of rocket and fuel
|
||||
sim.evaluate("m1 = 433100 kg") // First stage mass
|
||||
sim.evaluate("m2 = 111500 kg") // Second stage mass
|
||||
sim.evaluate("m3 = 1700 kg") // Third stage / fairing mass
|
||||
sim.evaluate("mp = 5000 kg") // Payload mass
|
||||
sim.evaluate("m0 = m1+m2+m3+mp") // Initial mass of rocket
|
||||
sim.evaluate("dm = 2750 kg/s") // Mass flow rate
|
||||
sim.evaluate("A = (3.66 m)^2 * pi") // Area of the rocket
|
||||
sim.evaluate("dragCoef = 0.2") // Drag coefficient
|
||||
|
||||
// Define the equations of motion. It is important to maintain the same argument order for each of these functions.
|
||||
sim.evaluate("drdt(r, v, m, phi, gamma) = v sin(gamma)")
|
||||
sim.evaluate("dvdt(r, v, m, phi, gamma) = -mu / r^2 * sin(gamma) + T / m")
|
||||
sim.evaluate("dmdt(r, v, m, phi, gamma) = -T/g0/isp")
|
||||
sim.evaluate("dphidt(r, v, m, phi, gamma) = v/r * cos(gamma) * rad")
|
||||
sim.evaluate("dgammadt(r, v, m, phi, gamma) = (1/r * (v - mu / (r v)) * cos(gamma)) * rad")
|
||||
// Define the equations of motion. We just thrust into current direction of motion, e.g. making a gravity turn.
|
||||
sim.evaluate("gravity(r) = mu / r^2")
|
||||
sim.evaluate("angVel(r, v, gamma) = v/r * cos(gamma) * rad") // Angular velocity of rocket around moon
|
||||
sim.evaluate("density(r) = 1.2250 kg/m^3 * exp(-g0 * (r - r0) / (83246.8 m^2/s^2))") // Assume constant temperature
|
||||
sim.evaluate("drag(r, v) = 1/2 * density(r) .* v.^2 * A * dragCoef")
|
||||
sim.evaluate("isp(r) = isp_vac + (isp_sea - isp_vac) * density(r)/density(r0)") // pressure ~ density for constant temperature
|
||||
sim.evaluate("thrust(isp) = g0 * isp * dm")
|
||||
// It is important to maintain the same argument order for each of these functions.
|
||||
sim.evaluate("drdt(r, v, m, phi, gamma, t) = v sin(gamma)")
|
||||
sim.evaluate("dvdt(r, v, m, phi, gamma, t) = - gravity(r) * sin(gamma) + (thrust(isp(r)) - drag(r, v)) / m")
|
||||
sim.evaluate("dmdt(r, v, m, phi, gamma, t) = - dm")
|
||||
sim.evaluate("dphidt(r, v, m, phi, gamma, t) = angVel(r, v, gamma)")
|
||||
sim.evaluate("dgammadt(r, v, m, phi, gamma, t) = angVel(r, v, gamma) - gravity(r) * cos(gamma) / v * rad")
|
||||
sim.evaluate("dtdt(r, v, m, phi, gamma, t) = 1")
|
||||
|
||||
// Again, remember to maintain the same variable order in the call to ndsolve.
|
||||
sim.evaluate("result_stage1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], [r0, v0, m0, phi0, gamma0], dt, tfinal)")
|
||||
// Remember to maintain the same variable order in the call to ndsolve.
|
||||
sim.evaluate("result_stage1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], [r0, v0, m0, phi0, gamma0, t0], dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for interstage flight
|
||||
sim.evaluate("T = 0 lbf")
|
||||
sim.evaluate("tfinal = 12 s")
|
||||
sim.evaluate("x = flatten(result_stage1[result_stage1.size()[1],:])")
|
||||
sim.evaluate("result_interstage = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
||||
|
||||
console.log(sim.evaluate("result_interstage[result_interstage.size()[1],3]").toString())
|
||||
sim.evaluate("dm = 0 kg/s")
|
||||
sim.evaluate("tfinal = 10 s")
|
||||
sim.evaluate("x = flatten(result_stage1[end,:])")
|
||||
sim.evaluate("x[3] = m2+m3+mp") // New mass after stage seperation
|
||||
sim.evaluate("result_interstage = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for stage 2 flight
|
||||
sim.evaluate("T = 210000 lbf")
|
||||
sim.evaluate("isp = 348 s")
|
||||
sim.evaluate("tfinal = 397 s")
|
||||
sim.evaluate("x = flatten(result_interstage[result_interstage.size()[1],:])")
|
||||
sim.evaluate("x[3] = 273600 lbm") // Lighten the rocket a bit since we discarded the first stage
|
||||
sim.evaluate("result_stage2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
||||
sim.evaluate("dm = 270.8 kg/s")
|
||||
sim.evaluate("isp_vac = 348 s")
|
||||
sim.evaluate("tfinal = 350 s")
|
||||
sim.evaluate("x = flatten(result_interstage[end,:])")
|
||||
sim.evaluate("result_stage2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for unpowered flight
|
||||
sim.evaluate("T = 0 lbf")
|
||||
sim.evaluate("tfinal = 60 s")
|
||||
sim.evaluate("x = flatten(result_stage2[result_stage2.size()[1],:])")
|
||||
sim.evaluate("result_unpowered = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
||||
sim.evaluate("dm = 0 kg/s")
|
||||
sim.evaluate("tfinal = 900 s")
|
||||
sim.evaluate("dt = 10 s")
|
||||
sim.evaluate("x = flatten(result_stage2[end,:])")
|
||||
sim.evaluate("result_unpowered1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for final orbit insertion
|
||||
sim.evaluate("dm = 270.8 kg/s")
|
||||
sim.evaluate("tfinal = 39 s")
|
||||
sim.evaluate("dt = 0.5 s")
|
||||
sim.evaluate("x = flatten(result_unpowered1[end,:])")
|
||||
sim.evaluate("result_insertion = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for unpowered flight
|
||||
sim.evaluate("dm = 0 kg/s")
|
||||
sim.evaluate("tfinal = 250 s")
|
||||
sim.evaluate("dt = 10 s")
|
||||
sim.evaluate("x = flatten(result_insertion[end,:])")
|
||||
sim.evaluate("result_unpowered2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Extract the useful information from the results so it can be plotted
|
||||
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]} })
|
||||
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]} })
|
||||
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]} })
|
||||
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]} })
|
||||
// Now it's time to prepare results for plotting
|
||||
const resultNames = ['stage1', 'interstage', 'stage2', 'unpowered1', 'insertion', 'unpowered2']
|
||||
.map(stageName => `result_${stageName}`)
|
||||
|
||||
window['chart'] = new Chart(document.getElementById('canvas1'), {
|
||||
// Concat result matrices
|
||||
sim.set('result',
|
||||
math.concat(
|
||||
...resultNames.map(resultName =>
|
||||
sim.evaluate(`${resultName}[:end-1, :]`) // Avoid overlap
|
||||
),
|
||||
0 // Concat in row-dimension
|
||||
)
|
||||
)
|
||||
|
||||
const mainDatasets = resultNames.map((resultName, i) => ({
|
||||
label: resultName.slice(7),
|
||||
data: sim.evaluate(
|
||||
'concat('
|
||||
+ `(${resultName}[:,4] - phi0) * r0 / rad / km,` // Surface distance from start (in km)
|
||||
+ `(${resultName}[:,1] - r0) / km` // Height above surface (in km)
|
||||
+ ')'
|
||||
).toArray().map(([x, y]) => ({ x, y })),
|
||||
borderColor: i % 2 ? '#999' : '#dc3912',
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
}))
|
||||
new Chart(document.getElementById('canvas'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: "Stage 1",
|
||||
data: data_stage1,
|
||||
fill: false,
|
||||
borderColor: "red",
|
||||
pointRadius: 0
|
||||
}, {
|
||||
label: "Interstage",
|
||||
data: data_interstage,
|
||||
fill: false,
|
||||
borderColor: "green",
|
||||
pointRadius: 0
|
||||
}, {
|
||||
label: "Stage 2",
|
||||
data: data_stage2,
|
||||
fill: false,
|
||||
borderColor: "orange",
|
||||
pointRadius: 0
|
||||
}, {
|
||||
label: "Unpowered",
|
||||
data: data_unpowered,
|
||||
fill: false,
|
||||
borderColor: "blue",
|
||||
pointRadius: 0
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
data: { datasets: mainDatasets },
|
||||
options: getMainChartOptions()
|
||||
})
|
||||
|
||||
createChart([{
|
||||
label: 'velocity (in m/s)',
|
||||
data: sim.evaluate("result[:,[2,6]]")
|
||||
.toArray()
|
||||
.map(([v, t]) => ({ x: t.toNumber('s'), y: v.toNumber('m/s') }))
|
||||
}])
|
||||
createChart([{
|
||||
label: 'height (in km)',
|
||||
data: sim.evaluate("concat((result[:, 1] - r0), result[:, 6])")
|
||||
.toArray()
|
||||
.map(([r, t]) => ({ x: t.toNumber('s'), y: r.toNumber('km') })),
|
||||
}])
|
||||
createChart([{
|
||||
label: 'gamma (in deg)',
|
||||
data: sim.evaluate("result[:, [5,6]]")
|
||||
.toArray()
|
||||
.map(([gamma, t]) => ({ x: t.toNumber('s'), y: gamma.toNumber('deg') })),
|
||||
}])
|
||||
createChart([{
|
||||
label: 'acceleration (in m/s^2)',
|
||||
data: sim.evaluate("concat(diff(result[:, 2]) ./ diff(result[:, 6]), result[:end-1, 6])")
|
||||
.toArray()
|
||||
.map(([acc, t]) => ({ x: t.toNumber('s'), y: acc.toNumber('m/s^2') })),
|
||||
}])
|
||||
createChart([{
|
||||
label: 'drag acceleration (in m/s^2)',
|
||||
data: sim.evaluate("concat(drag(result[:, 1], result[:, 2]) ./ result[:, 3], result[:, 6])")
|
||||
.toArray()
|
||||
.map(([dragAcc, t]) => ({ x: t.toNumber('s'), y: dragAcc.toNumber('m/s^2') })),
|
||||
}])
|
||||
createChart(
|
||||
[
|
||||
{
|
||||
data: sim.evaluate("result[:, [1,4]]")
|
||||
.toArray()
|
||||
.map(([r, phi]) => math.rotate([r.toNumber('km'), 0], phi))
|
||||
.map(([x, y]) => ({ x, y })),
|
||||
},
|
||||
{
|
||||
data: sim.evaluate("map(0:0.25:360, function(angle) = rotate([r0/km, 0], angle))")
|
||||
.toArray()
|
||||
.map(([x, y]) => ({ x, y })),
|
||||
borderColor: "#999",
|
||||
fill: true
|
||||
}
|
||||
],
|
||||
getEarthChartOptions()
|
||||
)
|
||||
|
||||
// Helper functions for plotting data (nothing to learn about math.js from here on)
|
||||
function createChart(datasets, options = {}) {
|
||||
const container = document.createElement("div")
|
||||
document.querySelector("#canvas-grid").appendChild(container)
|
||||
const canvas = document.createElement("canvas")
|
||||
container.appendChild(canvas)
|
||||
new Chart(canvas, {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: datasets.map(dataset => ({
|
||||
borderColor: "#dc3912",
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
...dataset
|
||||
}))
|
||||
},
|
||||
options: getChartOptions(options)
|
||||
})
|
||||
}
|
||||
|
||||
function getMainChartOptions() {
|
||||
return {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
position: 'bottom'
|
||||
position: 'bottom',
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'surface distance travelled (in km)'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: 'linear',
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'height above surface (in km)'
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
animation: false
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
function getChartOptions(options) {
|
||||
return {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
position: 'bottom',
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'time (in s)'
|
||||
}
|
||||
}]
|
||||
},
|
||||
animation: false,
|
||||
...options
|
||||
}
|
||||
}
|
||||
|
||||
function getEarthChartOptions() {
|
||||
return {
|
||||
aspectRatio: 1,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
position: 'bottom',
|
||||
min: -8000,
|
||||
max: 8000,
|
||||
display: false
|
||||
}],
|
||||
yAxes: [{
|
||||
type: 'linear',
|
||||
min: -8000,
|
||||
max: 8000,
|
||||
display: false
|
||||
}]
|
||||
},
|
||||
legend: { display: false }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
@ -9,157 +9,305 @@ File: [rocket_trajectory_optimization.html](rocket_trajectory_optimization.html)
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>math.js | rocket trajectory optimization</title>
|
||||
|
||||
<script src="https://unpkg.com/mathjs@8.1.1/lib/browser/math.js"></script>
|
||||
<script src="https://unpkg.com/mathjs@9.0.0/lib/browser/math.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#canvas-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 5%;
|
||||
margin-top: 5%;
|
||||
}
|
||||
|
||||
#canvas-grid>div {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Rocket trajectory optimization</h1>
|
||||
<p>
|
||||
This example simulates the ascent stage of the Apollo Lunar Module modeled using a system of ordinary differential equations.
|
||||
This example simulates the launch of a SpaceX Falcon 9 modeled using a system of ordinary differential equations.
|
||||
</p>
|
||||
|
||||
<canvas id=canvas1 width=1600 height=400></canvas>
|
||||
<canvas id=canvas2 width=800 height=400></canvas>
|
||||
<canvas id="canvas" width="1600" height="600"></canvas>
|
||||
<div id="canvas-grid"></div>
|
||||
|
||||
<script>
|
||||
|
||||
// Solve ODE `dx/dt = f(x,t), x(0) = x0` numerically.
|
||||
function ndsolve(f, x0, dt, tmax) {
|
||||
const n = f.size()[0] // Number of variables
|
||||
const x = x0.clone() // Current values of variables
|
||||
const dxdt = [] // Temporary variable to hold time-derivatives
|
||||
const result = [] // Contains entire solution
|
||||
|
||||
let x = x0.clone() // Current values of variables
|
||||
const result = [x] // Contains entire solution
|
||||
const nsteps = math.divide(tmax, dt) // Number of time steps
|
||||
for(let i=0; i<nsteps; i++) {
|
||||
for (let i = 0; i < nsteps; i++) {
|
||||
// Compute derivatives
|
||||
for(let j=0; j<n; j++) {
|
||||
dxdt[j] = f.get([j]).apply(null, x.toArray())
|
||||
}
|
||||
const dxdt = f.map(func => func(...x.toArray()))
|
||||
// Euler method to compute next time step
|
||||
for(let j=0; j<n; j++) {
|
||||
x.set([j], math.add(x.get([j]), math.multiply(dxdt[j], dt)))
|
||||
}
|
||||
result.push(x.clone())
|
||||
const dx = math.multiply(dxdt, dt)
|
||||
x = math.add(x, dx)
|
||||
result.push(x)
|
||||
}
|
||||
|
||||
return math.matrix(result)
|
||||
}
|
||||
|
||||
// Import the numerical ODE solver
|
||||
math.import({ndsolve:ndsolve})
|
||||
math.import({ ndsolve })
|
||||
|
||||
// Create a math.js context for our simulation. Everything else occurs in the context of the expression parser!
|
||||
|
||||
const sim = math.parser()
|
||||
|
||||
sim.evaluate("G = 6.67408e-11 m^3 kg^-1 s^-2") // Gravitational constant
|
||||
sim.evaluate("mbody = 5.972e24 kg") // Mass of Earth
|
||||
sim.evaluate("mu = G * mbody")
|
||||
sim.evaluate("dt = 1.0 s") // Simulation timestep
|
||||
sim.evaluate("tfinal = 162 s") // Simulation duration
|
||||
sim.evaluate("T = 1710000 lbf * 0.9") // Engine thrust
|
||||
sim.evaluate("mbody = 5.9724e24 kg") // Mass of Earth
|
||||
sim.evaluate("mu = G * mbody") // Standard gravitational parameter
|
||||
sim.evaluate("g0 = 9.80665 m/s^2") // Standard gravity: used for calculating prop consumption (dmdt)
|
||||
sim.evaluate("isp = 290 s") // Specific impulse
|
||||
sim.evaluate("gamma0 = 89.99883 deg") // Initial pitch angle (90 deg is vertical)
|
||||
sim.evaluate("r0 = 6378.1370 km") // Equatorial radius of Earth
|
||||
sim.evaluate("v0 = 10 m/s") // Initial velocity (must be non-zero because ODE is ill-conditioned)
|
||||
sim.evaluate("r0 = 6371 km") // Mean radius of Earth
|
||||
sim.evaluate("t0 = 0 s") // Simulation start
|
||||
sim.evaluate("dt = 0.5 s") // Simulation timestep
|
||||
sim.evaluate("tfinal = 149.5 s") // Simulation duration
|
||||
sim.evaluate("isp_sea = 282 s") // Specific impulse (at sea level)
|
||||
sim.evaluate("isp_vac = 311 s") // Specific impulse (in vacuum)
|
||||
sim.evaluate("gamma0 = 89.99970 deg") // Initial pitch angle (90 deg is vertical)
|
||||
sim.evaluate("v0 = 1 m/s") // Initial velocity (must be non-zero because ODE is ill-conditioned)
|
||||
sim.evaluate("phi0 = 0 deg") // Initial orbital reference angle
|
||||
sim.evaluate("m0 = 1207920 lbm + 30000 lbm") // Initial mass of rocket and fuel
|
||||
sim.evaluate("m1 = 433100 kg") // First stage mass
|
||||
sim.evaluate("m2 = 111500 kg") // Second stage mass
|
||||
sim.evaluate("m3 = 1700 kg") // Third stage / fairing mass
|
||||
sim.evaluate("mp = 5000 kg") // Payload mass
|
||||
sim.evaluate("m0 = m1+m2+m3+mp") // Initial mass of rocket
|
||||
sim.evaluate("dm = 2750 kg/s") // Mass flow rate
|
||||
sim.evaluate("A = (3.66 m)^2 * pi") // Area of the rocket
|
||||
sim.evaluate("dragCoef = 0.2") // Drag coefficient
|
||||
|
||||
// Define the equations of motion. It is important to maintain the same argument order for each of these functions.
|
||||
sim.evaluate("drdt(r, v, m, phi, gamma) = v sin(gamma)")
|
||||
sim.evaluate("dvdt(r, v, m, phi, gamma) = -mu / r^2 * sin(gamma) + T / m")
|
||||
sim.evaluate("dmdt(r, v, m, phi, gamma) = -T/g0/isp")
|
||||
sim.evaluate("dphidt(r, v, m, phi, gamma) = v/r * cos(gamma) * rad")
|
||||
sim.evaluate("dgammadt(r, v, m, phi, gamma) = (1/r * (v - mu / (r v)) * cos(gamma)) * rad")
|
||||
// Define the equations of motion. We just thrust into current direction of motion, e.g. making a gravity turn.
|
||||
sim.evaluate("gravity(r) = mu / r^2")
|
||||
sim.evaluate("angVel(r, v, gamma) = v/r * cos(gamma) * rad") // Angular velocity of rocket around moon
|
||||
sim.evaluate("density(r) = 1.2250 kg/m^3 * exp(-g0 * (r - r0) / (83246.8 m^2/s^2))") // Assume constant temperature
|
||||
sim.evaluate("drag(r, v) = 1/2 * density(r) .* v.^2 * A * dragCoef")
|
||||
sim.evaluate("isp(r) = isp_vac + (isp_sea - isp_vac) * density(r)/density(r0)") // pressure ~ density for constant temperature
|
||||
sim.evaluate("thrust(isp) = g0 * isp * dm")
|
||||
// It is important to maintain the same argument order for each of these functions.
|
||||
sim.evaluate("drdt(r, v, m, phi, gamma, t) = v sin(gamma)")
|
||||
sim.evaluate("dvdt(r, v, m, phi, gamma, t) = - gravity(r) * sin(gamma) + (thrust(isp(r)) - drag(r, v)) / m")
|
||||
sim.evaluate("dmdt(r, v, m, phi, gamma, t) = - dm")
|
||||
sim.evaluate("dphidt(r, v, m, phi, gamma, t) = angVel(r, v, gamma)")
|
||||
sim.evaluate("dgammadt(r, v, m, phi, gamma, t) = angVel(r, v, gamma) - gravity(r) * cos(gamma) / v * rad")
|
||||
sim.evaluate("dtdt(r, v, m, phi, gamma, t) = 1")
|
||||
|
||||
// Again, remember to maintain the same variable order in the call to ndsolve.
|
||||
sim.evaluate("result_stage1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], [r0, v0, m0, phi0, gamma0], dt, tfinal)")
|
||||
// Remember to maintain the same variable order in the call to ndsolve.
|
||||
sim.evaluate("result_stage1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], [r0, v0, m0, phi0, gamma0, t0], dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for interstage flight
|
||||
sim.evaluate("T = 0 lbf")
|
||||
sim.evaluate("tfinal = 12 s")
|
||||
sim.evaluate("x = flatten(result_stage1[result_stage1.size()[1],:])")
|
||||
sim.evaluate("result_interstage = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
||||
|
||||
console.log(sim.evaluate("result_interstage[result_interstage.size()[1],3]").toString())
|
||||
sim.evaluate("dm = 0 kg/s")
|
||||
sim.evaluate("tfinal = 10 s")
|
||||
sim.evaluate("x = flatten(result_stage1[end,:])")
|
||||
sim.evaluate("x[3] = m2+m3+mp") // New mass after stage seperation
|
||||
sim.evaluate("result_interstage = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for stage 2 flight
|
||||
sim.evaluate("T = 210000 lbf")
|
||||
sim.evaluate("isp = 348 s")
|
||||
sim.evaluate("tfinal = 397 s")
|
||||
sim.evaluate("x = flatten(result_interstage[result_interstage.size()[1],:])")
|
||||
sim.evaluate("x[3] = 273600 lbm") // Lighten the rocket a bit since we discarded the first stage
|
||||
sim.evaluate("result_stage2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
||||
sim.evaluate("dm = 270.8 kg/s")
|
||||
sim.evaluate("isp_vac = 348 s")
|
||||
sim.evaluate("tfinal = 350 s")
|
||||
sim.evaluate("x = flatten(result_interstage[end,:])")
|
||||
sim.evaluate("result_stage2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for unpowered flight
|
||||
sim.evaluate("T = 0 lbf")
|
||||
sim.evaluate("tfinal = 60 s")
|
||||
sim.evaluate("x = flatten(result_stage2[result_stage2.size()[1],:])")
|
||||
sim.evaluate("result_unpowered = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt], x, dt, tfinal)")
|
||||
sim.evaluate("dm = 0 kg/s")
|
||||
sim.evaluate("tfinal = 900 s")
|
||||
sim.evaluate("dt = 10 s")
|
||||
sim.evaluate("x = flatten(result_stage2[end,:])")
|
||||
sim.evaluate("result_unpowered1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for final orbit insertion
|
||||
sim.evaluate("dm = 270.8 kg/s")
|
||||
sim.evaluate("tfinal = 39 s")
|
||||
sim.evaluate("dt = 0.5 s")
|
||||
sim.evaluate("x = flatten(result_unpowered1[end,:])")
|
||||
sim.evaluate("result_insertion = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Reset initial conditions for unpowered flight
|
||||
sim.evaluate("dm = 0 kg/s")
|
||||
sim.evaluate("tfinal = 250 s")
|
||||
sim.evaluate("dt = 10 s")
|
||||
sim.evaluate("x = flatten(result_insertion[end,:])")
|
||||
sim.evaluate("result_unpowered2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")
|
||||
|
||||
// Extract the useful information from the results so it can be plotted
|
||||
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]} })
|
||||
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]} })
|
||||
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]} })
|
||||
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]} })
|
||||
// Now it's time to prepare results for plotting
|
||||
const resultNames = ['stage1', 'interstage', 'stage2', 'unpowered1', 'insertion', 'unpowered2']
|
||||
.map(stageName => `result_${stageName}`)
|
||||
|
||||
window['chart'] = new Chart(document.getElementById('canvas1'), {
|
||||
// Concat result matrices
|
||||
sim.set('result',
|
||||
math.concat(
|
||||
...resultNames.map(resultName =>
|
||||
sim.evaluate(`${resultName}[:end-1, :]`) // Avoid overlap
|
||||
),
|
||||
0 // Concat in row-dimension
|
||||
)
|
||||
)
|
||||
|
||||
const mainDatasets = resultNames.map((resultName, i) => ({
|
||||
label: resultName.slice(7),
|
||||
data: sim.evaluate(
|
||||
'concat('
|
||||
+ `(${resultName}[:,4] - phi0) * r0 / rad / km,` // Surface distance from start (in km)
|
||||
+ `(${resultName}[:,1] - r0) / km` // Height above surface (in km)
|
||||
+ ')'
|
||||
).toArray().map(([x, y]) => ({ x, y })),
|
||||
borderColor: i % 2 ? '#999' : '#dc3912',
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
}))
|
||||
new Chart(document.getElementById('canvas'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: "Stage 1",
|
||||
data: data_stage1,
|
||||
fill: false,
|
||||
borderColor: "red",
|
||||
pointRadius: 0
|
||||
}, {
|
||||
label: "Interstage",
|
||||
data: data_interstage,
|
||||
fill: false,
|
||||
borderColor: "green",
|
||||
pointRadius: 0
|
||||
}, {
|
||||
label: "Stage 2",
|
||||
data: data_stage2,
|
||||
fill: false,
|
||||
borderColor: "orange",
|
||||
pointRadius: 0
|
||||
}, {
|
||||
label: "Unpowered",
|
||||
data: data_unpowered,
|
||||
fill: false,
|
||||
borderColor: "blue",
|
||||
pointRadius: 0
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
data: { datasets: mainDatasets },
|
||||
options: getMainChartOptions()
|
||||
})
|
||||
|
||||
createChart([{
|
||||
label: 'velocity (in m/s)',
|
||||
data: sim.evaluate("result[:,[2,6]]")
|
||||
.toArray()
|
||||
.map(([v, t]) => ({ x: t.toNumber('s'), y: v.toNumber('m/s') }))
|
||||
}])
|
||||
createChart([{
|
||||
label: 'height (in km)',
|
||||
data: sim.evaluate("concat((result[:, 1] - r0), result[:, 6])")
|
||||
.toArray()
|
||||
.map(([r, t]) => ({ x: t.toNumber('s'), y: r.toNumber('km') })),
|
||||
}])
|
||||
createChart([{
|
||||
label: 'gamma (in deg)',
|
||||
data: sim.evaluate("result[:, [5,6]]")
|
||||
.toArray()
|
||||
.map(([gamma, t]) => ({ x: t.toNumber('s'), y: gamma.toNumber('deg') })),
|
||||
}])
|
||||
createChart([{
|
||||
label: 'acceleration (in m/s^2)',
|
||||
data: sim.evaluate("concat(diff(result[:, 2]) ./ diff(result[:, 6]), result[:end-1, 6])")
|
||||
.toArray()
|
||||
.map(([acc, t]) => ({ x: t.toNumber('s'), y: acc.toNumber('m/s^2') })),
|
||||
}])
|
||||
createChart([{
|
||||
label: 'drag acceleration (in m/s^2)',
|
||||
data: sim.evaluate("concat(drag(result[:, 1], result[:, 2]) ./ result[:, 3], result[:, 6])")
|
||||
.toArray()
|
||||
.map(([dragAcc, t]) => ({ x: t.toNumber('s'), y: dragAcc.toNumber('m/s^2') })),
|
||||
}])
|
||||
createChart(
|
||||
[
|
||||
{
|
||||
data: sim.evaluate("result[:, [1,4]]")
|
||||
.toArray()
|
||||
.map(([r, phi]) => math.rotate([r.toNumber('km'), 0], phi))
|
||||
.map(([x, y]) => ({ x, y })),
|
||||
},
|
||||
{
|
||||
data: sim.evaluate("map(0:0.25:360, function(angle) = rotate([r0/km, 0], angle))")
|
||||
.toArray()
|
||||
.map(([x, y]) => ({ x, y })),
|
||||
borderColor: "#999",
|
||||
fill: true
|
||||
}
|
||||
],
|
||||
getEarthChartOptions()
|
||||
)
|
||||
|
||||
// Helper functions for plotting data (nothing to learn about math.js from here on)
|
||||
function createChart(datasets, options = {}) {
|
||||
const container = document.createElement("div")
|
||||
document.querySelector("#canvas-grid").appendChild(container)
|
||||
const canvas = document.createElement("canvas")
|
||||
container.appendChild(canvas)
|
||||
new Chart(canvas, {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: datasets.map(dataset => ({
|
||||
borderColor: "#dc3912",
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
...dataset
|
||||
}))
|
||||
},
|
||||
options: getChartOptions(options)
|
||||
})
|
||||
}
|
||||
|
||||
function getMainChartOptions() {
|
||||
return {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
position: 'bottom'
|
||||
position: 'bottom',
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'surface distance travelled (in km)'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: 'linear',
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'height above surface (in km)'
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
animation: false
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
function getChartOptions(options) {
|
||||
return {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
position: 'bottom',
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'time (in s)'
|
||||
}
|
||||
}]
|
||||
},
|
||||
animation: false,
|
||||
...options
|
||||
}
|
||||
}
|
||||
|
||||
function getEarthChartOptions() {
|
||||
return {
|
||||
aspectRatio: 1,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
position: 'bottom',
|
||||
min: -8000,
|
||||
max: 8000,
|
||||
display: false
|
||||
}],
|
||||
yAxes: [{
|
||||
type: 'linear',
|
||||
min: -8000,
|
||||
max: 8000,
|
||||
display: false
|
||||
}]
|
||||
},
|
||||
legend: { display: false }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
<!-- Note: This file is automatically generated. Changes made in this file will be overridden. -->
|
||||
|
||||
@ -92,7 +92,7 @@ File: [webworkers.html](webworkers.html) (click for a live demo)
|
||||
File: [worker.js](worker.js)
|
||||
|
||||
```js
|
||||
importScripts('https://unpkg.com/mathjs@8.1.1/lib/browser/math.js')
|
||||
importScripts('https://unpkg.com/mathjs@9.0.0/lib/browser/math.js')
|
||||
|
||||
// create a parser
|
||||
const parser = self.math.parser()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
importScripts('https://unpkg.com/mathjs@8.1.1/lib/browser/math.js')
|
||||
importScripts('https://unpkg.com/mathjs@9.0.0/lib/browser/math.js')
|
||||
|
||||
// create a parser
|
||||
const parser = self.math.parser()
|
||||
|
||||
15
history.md
15
history.md
@ -4,6 +4,21 @@ layout: default
|
||||
|
||||
<h1 id="history">History <a href="#history" title="Permalink">#</a></h1>
|
||||
|
||||
<h1 id="20210116-version-900">2021-01-16, version 9.0.0 <a href="#20210116-version-900" title="Permalink">#</a></h1>
|
||||
|
||||
- Improved support for bin, hex, and oct literals. See <a href="https://github.com/josdejong/mathjs/issues/1996">#1996</a>. Thanks <a href="https://github.com/clnhlzmn">@clnhlzmn</a>.
|
||||
- **Breaking change**: parse literals with prefixes `0b`, `0c`, and `0x` are
|
||||
now unsigned by default. To parse them as signed, you have to specify a
|
||||
suffix specifying the word size such as `i16` or `i32`.
|
||||
- Function `format` now supports more notations: `bin`, 'hex', and `oct`,
|
||||
for example `format(255, {notation: "hex"})`.
|
||||
- The functions `format`, `bin`, `hex`, `oct` now allow specifying a wordSize,
|
||||
like `bin(10, 32)` and `format(10, {notation: "bin", wordSize: 32})`.
|
||||
- BigNumber support for the bin, hex, and oct literals.
|
||||
- Extended and improved the example rocket_trajectory_optimization.html.
|
||||
Thanks <a href="https://github.com/Josef37">@Josef37</a>.
|
||||
|
||||
|
||||
<h1 id="20201230-version-811">2020-12-30, version 8.1.1 <a href="#20201230-version-811" title="Permalink">#</a></h1>
|
||||
|
||||
- Improved the performance of parsing and evaluating units a lot, see <a href="https://github.com/josdejong/mathjs/issues/2065">#2065</a>.
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12
package-lock.json
generated
12
package-lock.json
generated
@ -1902,9 +1902,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true
|
||||
},
|
||||
"interpret": {
|
||||
@ -2319,9 +2319,9 @@
|
||||
}
|
||||
},
|
||||
"mathjs": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-8.1.1.tgz",
|
||||
"integrity": "sha512-b3TX3EgiZObujjwb8lZnTDLUuivC2jar4ZBjmGJ4stFYCDXx/DNwx5yry5t/z65p9mvejyZel1qoeR05KtChcQ==",
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.0.0.tgz",
|
||||
"integrity": "sha512-ZfNz90wyed1MJUQOfL+Jr9IWG6vevVPM+cFf93sV568lbY8w2obEv5Ba7e7+Ylg5Zv0PTPtEY5CbqivHw/AxGQ==",
|
||||
"requires": {
|
||||
"complex.js": "^2.0.11",
|
||||
"decimal.js": "^10.2.1",
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"url": "https://github.com/josdejong/mathjs.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"mathjs": "8.1.1"
|
||||
"mathjs": "9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fancy-log": "1.3.3",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user