Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions lib/AstrodynamicalCalculations/docs/src/_quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ book:
date: "2025-03-02"
chapters:
- index.md
- part: examples/index.qmd
chapters:
- examples/circular-two-body/index.qmd
- examples/keplerian/index.qmd
- examples/circular-three-body/index.qmd
- part: api/index.qmd
chapters:
- api/r2b/index.qmd
Expand All @@ -34,10 +39,8 @@ book:
toc-title: "Table of Contents"

execute:
echo: false
echo: true
output: true
cache: false
freeze: false

bibliography: references.bib

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
---
number-depth: 2
---

# Orbits in Circular Three Body Dynamics

*Orbits in e.g. the Earth-Moon system.*

```{julia}
using LinearAlgebra
using AstrodynamicalCalculations
```

## Coordinate Conversions

The Circular Restricted Three Body (CR3B) Problem describes a massless spacecraft experiencing gravitational forces due to *two* point masses which orbit their common center of mass.
There's a good bit there, so let's unpack that statement further.
Consider the Earth and its moon.
The Earth and the Moon both orbit the Sun, but if we neglect the Sun and watch the positions of the Earth and the Moon with respect to their common center of mass (in a rotating reference frame where the $\hat{x}$ axis points from the Earth to the Moon) then both the Earth and the Moon appear to move along *circular* orbits.

When we analyze orbits within this problem, we typically use non-dimensional units: we scale all distance units by the distance $a$ between the two massive bodies, and we scale all time distances by the following function of $a$ and each body's mass parameter: $2\pi \sqrt{\frac{a^3}{\mu_1 + \mu_2}}$.

```{julia}
a = 1e5 # TODO replace with real value
μ₁ = 1e5 # TODO replace with real value
μ₂ = 14 # TODO replace with real value
```

Both of these scalings are provided by the `distance_scaling` and `time_scaling` functions.
The `velocity_scaling` is simply the result of the `distance_scaling` divided by the `time_scaling`.

```{julia}
L = distance_scaling(a, μ₁, μ₂)
```

```{julia}
T = time_scaling(a, μ₁, μ₂)
```

```{julia}
V = velocity_scaling(a, μ₁, μ₂)
```

These scalings are applied to Cartesian state vectors in CR3B dynamics.

```{julia}
c = (; x = 1e6, y = -1e2, z = 3e3, ẋ = 1e2, ẏ = -1e3, ż = 0.0)
t = 1e9

c = nondimensional(c..., t, a, μ₁, μ₂)
```

::: {.callout-important appearance="simple"}
All CR3B calculations are performed using **nondimensional** units in the Synodic (rotating) reference frame!
:::

Given a particular Synodic (rotating reference frame) position $\overrightarrow{x}$, we can also compute the corresponding distance to the primary and secondary bodies using `distance_to_primary` and `distance_to_secondary` respectively.

```{julia}
r = norm((c.x, c.y, c.z))
```

```{julia}
r₁ = distance_to_primary(r, c.μ)
```

```{julia}
r₂ = distance_to_secondary(r, c.μ)
```

As mentioned above, all calculations are performed in the Synodic (rotating) reference frame.
We can convert nondimensional Cartesian coordinates expressed in the Synodic frame to the barycentric inertial frame (an inertial frame centered at the center of mass of the system) using the `synodic_to_inertial` function with two additional pieces of information: the time $t$ since the coordinate frame epoch and the angular speed of the massive bodies $\omega$.

```{julia}
let t = 0.1, ω = 1.0
synodic_to_inertial(c.x, c.y, c.z, t, ω)
end
```

## Energy Calculations

As always, we can compute the potential energy of the orbit using the `potential_energy` function.

```{julia}
P = potential_energy(c.x, c.y, c.z, c.μ)
```

There is a second metric for measuring orbital energies in CR3B dynamics: the so-called Jacobi constant $C \triangleq 2 P - v^2$.
We can use the `jacobi_constant` function to compute this value.

```{julia}
C = jacobi_constant(c.x, c.y, c.z, c.ẋ, c.ẏ, c.ż, c.μ)
```

Every CR3B system has the potential for *contours* of zero-velocity dynamics: a spacecraft in the system may never cross such lines in state space.
The `zero_velocity_curves` function computes these contours as collections of $(x,y)$ lines.

## Lagrange Points

As is the case for all nonlinear dynamical systems, there are special positions in state space where the induced accelerations are null.
In CR3B dynamics, these points are known as Lagrange points.
In theory, a spacecraft placed at one of these points will stay there for all time.
In practice, of course, no system perfectly satisfies the assumptions set by the CR3B definition.
Still, these points *are* practically useful, as demonstrated by e.g. the James Webb Space Telescope's orbit about an Earth-Moon Lagrange point.

There are $5$ Lagrange points for every CR3B system: three along the $x$ axis, and two offset points which are mirrored across the $x$ axis.
The positions for each of these points can be found using the `lagrange_point` function, given the nondimensional mass parameter $\mu$ for the CR3B system.

```{julia}
let L = 1:5
L .=> lagrange_point.(c.μ, L)
end
```

## Approximate Periodic Orbits

There exist periodic orbits about Lagrange points in CR3B dynamics.
Periodic orbits in three dimensions (extra-planar orbits) are known as *halo* orbits.
Periodic orbits in two dimensions (planar orbits) are known as *Lyapunov* orbits.
These orbits can only be found using (quite sensitive) numerical methods: these capabilities are provided by `AstrodynamicalSolvers.jl`, and are described in the package [documentation](https://JuliaAstro.org/GeneralAstrodynamics/lib/AstrodynamicalSolvers).
Approximations for periodic initial conditions are available analytically, and this is provided in `AstrodynamicalCalculations` through the `richardson_ic` function.

```{julia}
let L = 2, Z = 1e-3
ic = richardson_ic(c.μ, L; Z = Z)
end
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
number-depth: 2
---

# Circular Orbits

_The simplest possible orbit._

```{julia}
using LinearAlgebra
using AstrodynamicalCalculations
```

## Coordinate Conversions

If we assume a mass-less spacecraft orbiting a point mass, perfectly circular orbits are possible.
The eccentricity of circular orbits is (by definition) zero.
We can confirm this using the `conic` function.

```{julia}
let e = 0
conic(e)
end
```

We can construct a fully specified circular orbit by specifying Keplerian parameters (orbital elements).
The mass parameter `μ` is the mass of the body we are orbiting multiplied by gravitational constant $G$.

```{julia}
k = (; e = 0, a = 10e5, i = π / 4, Ω = 0, ω = 0, ν = π / 2)
μ = 3.1e10
```

With our orbit specified in Keplerian parameters, we may ask: what are the Cartesian coordinates of the orbit?

:::{.callout-info appearance="simple"}
The Cartesian coordinates are defined _with respect to_ the center of the primary body (the body that is being orbited), and _expressed in_ the coordinate frame defined by the primary body.
:::

```{julia}
c = keplerian_to_cartesian(k..., μ)
```

We can also take Cartesian coordinates and convert them back to Keplerian coordinates.

:::{.callout-warning appearance="simple"}
The transformation from Keplerian to Cartesian coordinates is _not_ the inverse of the transformation from Cartesian to Keplerian coordinates!
:::

```{julia}
cartesian_to_keplerian(c..., μ)
```

## Energy Calculations

Every (restricted) orbit has an associated specific energy: the energy of the orbit per unit mass.
An associated parameter is the $C_3$ energy, which is defined as $v^2 - \frac{2\mu}{r}$, where $v$ and $r$ are the scalar instantaneous orbital speed and radius values respectively.

```{julia}
specific_energy(c..., μ)
```

```{julia}
c3(c..., μ)
```

The specific potential energy includes the potential energy per unit mass.
Of course, the velocity components of the Cartesian state are not relevant to the calculation!
For convenience, you can still provide the full Cartesian state in the method: the calculation will simply discard the velocity components.

```{julia}
P = specific_potential_energy(c..., μ)
```

```{julia}
@assert P == specific_potential_energy(norm([c.x, c.y, c.z]), μ)
```

## Orbital Characterizations

Simple characterizations, such as the instantaneous orbital speed, orbital radius, or semi-parameter, are also available.

```{julia}
r = orbital_radius(c..., μ)
```

```{julia}
v = orbital_speed(c..., μ)
```

```{julia}
p = semi_parameter(c..., μ)
```

:::{.callout-tip appearance="simple"}
For circular orbits, the semi-parameter $p$ is equivalent to the orbital radius $r$!
:::

## Next Steps

Circular orbits are quite simple problems to solve; they are a special case of Keplerian orbits in general.
The following usage example presents non-circular Keplerian orbits, and the additional calculations that are relevant to such problems, e.g. eccentricity, the periapsis radius, and the apoapsis radius.
19 changes: 19 additions & 0 deletions lib/AstrodynamicalCalculations/docs/src/examples/index.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
number-depth: 2
---

# Examples

_Usage examples for `AstrodynamicalCalculations`._

All following subsections show how various astrodynamics calculations can be performed using `AstrodynamicalCalculations`.
As mentioned previously, you can install `AstrodynamicalCalculations` using one of the lines below.

```julia
import Pkg
Pkg.add("AstrodynamicalCalculations")
```

```julia
pkg> add AstrodynamicalCalculations
```
Loading
Loading