Skip to content

Phim226/orbit-visualiser

Repository files navigation

Orbit Visualiser

The Orbit Visualiser is a 3D Keplerian orbit visualisation tool for modelling the motion of a satellite around a central body, written in Python. The focus of this tool is on orbital geometry and satellite kinematics. Has basic orbital propagation (currently no GUI functionality).

3d-demo-2

Features

Orbits are modelled and visualised in the Earth Centred Equatorial (ECI) frame, with the orbital geometry parametrised using:

  • Eccentricity
  • Radius of periapsis
  • Right ascension of the ascending node
  • Inclination
  • Argument of periapsis

The central body has a radius of 6738km and an adjustable gravitational parameter. The radius of periapsis has therefore been given a lower limit of 6739km (meaning that we are assuming this Earth sized body has no atmosphere, or at least that any atmosphere has no effect on orbital motion). The true anomaly of the orbiting satellite is also adjustable to evaluate the kinematic state at different orbital positions. Various orbital and kinematic quantities are calculated and displayed, including (but not limited to):

  • Semi-major/minor axis
  • Radius of apoapsis
  • True anomaly of the asymptote (for parabolic and hyperbolic trajectories)
  • Specific angular momentum
  • Radial velocity
  • Azimuthal velocity
  • Escape velocity
  • Hyperbolic excess velocity
  • Time since periapsis

See the gif above for the full list of displayed orbital and kinematic properties.

Planned Features

There are several features that are in development or planned:

  • Additional display options
  • A web interface
  • Option to change reference frame
  • Option to change parametrisation of orbital geometry

Notes on the physical model

The orbiting satellite is assumed to have negligible mass. All higher-order perturbations, such as atmospheric drag or oblateness, are ignored.

Potential future improvements

  • Improve simulation of orbital motion
  • Include perturbations into the model
  • Expand modelling to R3BP or N-body system
  • Visualise gravitational field

Requirements

  • Python 3.8 or later
  • Git (optional but recommended, for cloning the repository)

Python dependencies

  • numpy
  • matplotlib
  • scipy

These are also listed in requirements.txt.

How to use

Clone the repository:

git clone https://github.com/Phim226/orbit-visualiser.git

Navigate to the project folder:

cd orbit-visualiser

Create a virtual environment:

python3 -m venv .venv

Activate the environment:

Windows

Windows Powershell:

.venv\Scripts\Activate.ps1
  • Warning: On some Windows systems, Powershell might block this command depending on the script execution policy. If you see an error like:

    ...\.venv\Scripts\Activate.ps1 cannot be loaded because running scripts is disabled on this system.

    Then you can run:

    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process

    to temporarily allow scripts in the current terminal session.

Windows Command Prompt:

.venv\Scripts\activate.bat

This should work without changing any execution policies.

Linux/macOS

source .venv/bin/activate

If you see (.venv) at the start of your prompt, then the virtual environment is active.

Install dependencies and the package in editable mode (make sure this is done within the virtual environment):

python3 -m pip install --upgrade pip
pip install -r requirements.txt

The -e in requirements.txt ensures that the package is editable, which ensures that any changes to the source code are immediately reflected when running the program.

Run the program:

python src/orbit_visualiser/main.py

When you're finished using the program or making changes then run:

deactivate

to deactivate the virtual environment. When returning to the program, activate venv again using the commands above. So long as the project folder or .venv folder hasn't changed then you shouldn't need to reinstall any dependencies.

Using Orbit Propagation

As of the current version (v0.4.5) there is no CLI or GUI functionality for the orbit propagation. Navigate to src/orbit_visualiser/core/propagation.py, and go to the bottom of the file to the code snippet:

if __name__ == "__main__":

    orbit = Orbit.from_orbital_elements(e = 0.0, rp = 50_000.0, nu = 0.0, raan = 0.0, i = 0.0,
                                        omega = 0.0, mu = 398_600.0,)

    sol = run_orbit_prop(orbit, orbit.orbital_period)

    init_conditions = get_init_conditions_from_orbit(orbit)
    print(init_conditions)
    print(sol.y[:, -1])

    r0 = np.linalg.norm(init_conditions[:3])
    rf = np.linalg.norm(sol.y[:3, -1])

    print(f"Difference in radius after propagating: {rf - r0}")

The orbit propagation function takes the Orbit object and propagation end time (the start time is always 0, and begins the propagation at the true anomaly (nu) set in the constructor Orbit.from_orbital_elements). The values set in the code snippet above result in the propagation of a circular orbit of radius 50,000km, starting at the perifocal position (50000, 0, 0) lasting for one orbital period. For non-circular orbits nu = 0.0 is periapsis. The true anomaly is in radians, so nu = pi is apoapsis.

In order to get accurate results you should keep the end time on the order of 10 or at most 100 periods. The integrators used by scipy aren't symplectic, so there is significant energy drift over longer propagations.

There is a third optional argument of run_orbit_prop called period_frac_per_step: int = 500, which determines the time step as a function of the fraction of a single period. So the default value results in a time step equal to 1/500 of the orbital period (rounded up to the nearest integer).

The current print statements are just quick sanity checks to show that after a whole number of orbits the satellite is returning to roughly the same spot and with roughly the same velocity.

As an example if you wanted to propagate the ISS then you might edit the above code snippet to:

if __name__ == "__main__":
    # Approximate eccentricity, radius of periapsis (km), right ascension of the ascending node (rad),
    # inclination (rad) and argument of perigee (rad) for the ISS, with mu representing the
    # gravitational parameter of earth in km^3/s^2
    iss_orbit = Orbit.from_orbital_elements(e = 0.0002267, rp = 6778, nu = 0.0, raan = 4.319,
                                            i = 0.901, omega = 2.278, mu = 398_600.0)

    # Runs the propagation for 1 period, returning the ISS back to periapsis
    sol = run_orbit_prop(iss_orbit, iss_orbit.orbital_period)

    init_conditions = get_init_conditions_from_orbit(iss_orbit)
    print(init_conditions)

    # Grabs the array of solutions (sol.y) and prints the last entry
    print(sol.y[:, -1])

    r0 = np.linalg.norm(init_conditions[:3])
    rf = np.linalg.norm(sol.y[:3, -1])

    print(f"Difference in radius after propagating: {rf - r0}")

Then running the script will run the propagation and print out the results.

About

3D Keplerian orbit visualisation tool

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages