Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve los customizability #152

Merged
merged 8 commits into from
Feb 28, 2023
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
15 changes: 10 additions & 5 deletions paseos/actors/base_actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from loguru import logger
import pykep as pk
import numpy as np
from skspatial.objects import Sphere
from dotmap import DotMap

from ..communication.is_in_line_of_sight import is_in_line_of_sight
Expand All @@ -28,10 +27,8 @@ class BaseActor(ABC):
# Position if not defined by orbital parameters
_position = None

# Earth as a sphere (for now)
# TODO replace this in the future depending on central body
# Note that this needs to be specified in solar reference frame for now
_central_body_sphere = Sphere([0, 0, 0], 6371000)
# Is specified by user / paseos instance but required for line of sight computations
_central_body_sphere = None

# Central body this actor is orbiting
_central_body = None
Expand Down Expand Up @@ -148,6 +145,14 @@ def _check_init_value_sensibility(
def __str__(self):
return self.name

def set_central_body_shape(self, sphere) -> None:
"""Sets the central body of this actor.

Args:
sphere (skspatial.Sphere): Sphere blocking line of sight.
"""
self._central_body_sphere = sphere

def set_time(self, t: pk.epoch):
"""Updates the local time of the actor.

Expand Down
15 changes: 11 additions & 4 deletions paseos/communication/is_in_line_of_sight.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ def _is_in_line_of_sight_ground_station_to_spacecraft(
# Plot if requested
if plot:
from skspatial.plotting import plot_3d
from skspatial.objects import Sphere, Line, Point

central_body_sphere = Sphere([0, 0, 0], 6371000)
from skspatial.objects import Line, Point

def plot(gs_pos_t, sat_pos_t, t):
# Converting to geocentric
Expand All @@ -162,7 +160,7 @@ def plot(gs_pos_t, sat_pos_t, t):
sat_point = Point(r2)
line = Line(r1, r2 - r1)
plot_3d(
central_body_sphere.plotter(alpha=0.4),
spacecraft._central_body_sphere.plotter(alpha=0.4),
line.plotter(c="b"),
gs_point.plotter(c="r", s=100),
sat_point.plotter(c="r", s=100),
Expand Down Expand Up @@ -201,6 +199,9 @@ def is_in_line_of_sight(
type(actor).__name__ == "SpacecraftActor"
and type(other_actor).__name__ == "SpacecraftActor"
):
assert (
actor._central_body_sphere is not None
), f"Please set the central sphere on actor {actor} for line of sight computations."
return _is_in_line_of_sight_spacecraft_to_spacecraft(
actor, other_actor, epoch, plot
)
Expand All @@ -210,6 +211,9 @@ def is_in_line_of_sight(
):
if minimum_altitude_angle is None:
minimum_altitude_angle = actor._minimum_altitude_angle
assert (
other_actor._central_body_sphere is not None
), f"Please set the central sphere on actor {other_actor} for line of sight computations."
return _is_in_line_of_sight_ground_station_to_spacecraft(
actor, other_actor, epoch, minimum_altitude_angle, plot
)
Expand All @@ -219,6 +223,9 @@ def is_in_line_of_sight(
):
if minimum_altitude_angle is None:
minimum_altitude_angle = other_actor._minimum_altitude_angle
assert (
actor._central_body_sphere is not None
), f"Please set the central sphere on actor {actor} for line of sight computations."
return _is_in_line_of_sight_ground_station_to_spacecraft(
other_actor, actor, epoch, minimum_altitude_angle, plot
)
Expand Down
10 changes: 8 additions & 2 deletions paseos/paseos.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
from dotmap import DotMap
from loguru import logger
import pykep as pk
from skspatial.objects import Sphere

from paseos.actors.base_actor import BaseActor
from paseos.activities.activity_manager import ActivityManager
from paseos.utils.operations_monitor import OperationsMonitor


class PASEOS:
"""This class serves as the main interface with the user. It is designed
as a singleton to ensure we only have one instance running at any time."""
"""This class serves as the main interface with the user."""

# Config file of the simulation
_cfg = None
Expand All @@ -28,6 +28,9 @@ class PASEOS:
# The actor of the device this is running on
_local_actor = None

# TODO replace this in the future depending on central body
_central_body_sphere = None

# Handles registered activities
_activity_manager = None

Expand All @@ -51,12 +54,15 @@ def __init__(self, local_actor: BaseActor, cfg=None):
"""
logger.trace("Initializing PASEOS")
self._cfg = cfg
self._central_body_sphere = Sphere([0, 0, 0], cfg.comm.central_body_LOS_radius)
self._state = DotMap(_dynamic=False)
self._state.time = self._cfg.sim.start_time
self._known_actors = {}
self._local_actor = local_actor
# Update local actor time to simulation start time.
self.local_actor.set_time(pk.epoch(self._cfg.sim.start_time * pk.SEC2DAY))
# Set line of sight blocking sphere
self.local_actor.set_central_body_shape(self._central_body_sphere)
self._activity_manager = ActivityManager(
self, self._cfg.sim.activity_timestep, self._cfg.sim.time_multiplier
)
Expand Down
7 changes: 6 additions & 1 deletion paseos/power/is_in_eclipse.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
from loguru import logger


def is_in_eclipse(actor, central_body: pk.planet, t: pk.epoch, plot=False) -> bool:
def is_in_eclipse(
actor,
central_body: pk.planet,
t: pk.epoch,
plot=False,
) -> bool:
"""Checks whether the actor is currently in eclipse of central body.

Args:
Expand Down
5 changes: 4 additions & 1 deletion paseos/resources/default_cfg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ activity_timestep = 1.0 # [s] Internal timestep at which activities update, try
time_multiplier = 1.0 # [unitless] Defines how much real time passes

[io]
logging_interval = 10.0 # [s] after how many seconds should paseos log the actor status
logging_interval = 10.0 # [s] after how many seconds should paseos log the actor status

[comm]
central_body_LOS_radius = 6451000.0 # [m] radius of the sphere blocking line of sight, default is Earth radius + 80km (start of thermosphere)
9 changes: 9 additions & 0 deletions paseos/tests/communication_window_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

sys.path.append("../..")

from skspatial.objects import Sphere

from paseos import (
SpacecraftActor,
GroundstationActor,
Expand All @@ -14,6 +16,8 @@
import pykep as pk
import numpy as np

from test_utils import _PASEOS_TESTS_EARTH_RADIUS


def from_epoch_to_s(epoch: pk.epoch):
return (epoch.mjd2000 - pk.epoch(0).mjd2000) / pk.SEC2DAY
Expand Down Expand Up @@ -45,6 +49,8 @@ def setup_sentinel_example(t0):
central_body=earth,
)

sentinel2B.set_central_body_shape(Sphere([0, 0, 0], _PASEOS_TESTS_EARTH_RADIUS))

# Define ground station
maspalomas_groundstation = ActorBuilder.get_actor_scaffold(
name="maspalomas_groundstation", actor_type=GroundstationActor, epoch=t0
Expand Down Expand Up @@ -143,6 +149,9 @@ def test_communication_link_sat_to_sat():
central_body=earth,
)

sat1.set_central_body_shape(Sphere([0, 0, 0], _PASEOS_TESTS_EARTH_RADIUS))
sat2.set_central_body_shape(Sphere([0, 0, 0], _PASEOS_TESTS_EARTH_RADIUS))

# Add communication link
ActorBuilder.add_comm_device(sat1, device_name="link1", bandwidth_in_kbps=1)

Expand Down
6 changes: 5 additions & 1 deletion paseos/tests/line_of_sight_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

sys.path.append("../..")

from skspatial.objects import Sphere

from paseos import SpacecraftActor, ActorBuilder, GroundstationActor
from paseos.communication.is_in_line_of_sight import is_in_line_of_sight

import pykep as pk

from test_utils import get_default_instance
from test_utils import get_default_instance, _PASEOS_TESTS_EARTH_RADIUS


def test_los_between_sats():
Expand All @@ -18,8 +20,10 @@ def test_los_between_sats():

sat2 = ActorBuilder.get_actor_scaffold("sat2", SpacecraftActor, pk.epoch(0))
ActorBuilder.set_orbit(sat2, [0, 10000000, 0], [0, 0, 8000.0], pk.epoch(0), earth)
sat2.set_central_body_shape(Sphere([0, 0, 0], _PASEOS_TESTS_EARTH_RADIUS))

sat3 = ActorBuilder.get_actor_scaffold("sat3", SpacecraftActor, pk.epoch(0))
sat3.set_central_body_shape(Sphere([0, 0, 0], _PASEOS_TESTS_EARTH_RADIUS))
ActorBuilder.set_orbit(sat3, [0, -10000000, 0], [0, 0, -8000.0], pk.epoch(0), earth)

# check that LOS is correct
Expand Down
2 changes: 2 additions & 0 deletions paseos/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import pykep as pk

_PASEOS_TESTS_EARTH_RADIUS = 6371000


def get_default_instance() -> (paseos.PASEOS, SpacecraftActor, pk.planet):
"""Sets up a instance of paseos with a satellite in orbit around Earth"""
Expand Down
7 changes: 4 additions & 3 deletions paseos/utils/check_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def check_cfg(cfg: DotMap):
Args:
cfg (DotMap): Run config you intend to use.
"""
major_categories = ["sim", "io"]
major_categories = ["sim", "io", "comm"]
_check_for_keys(cfg, major_categories)
_check_entry_types(cfg, major_categories)
_check_value_ranges(cfg, major_categories)
Expand All @@ -23,6 +23,7 @@ def _check_for_keys(cfg: DotMap, major_categories: list) -> None:
"activity_timestep",
"time_multiplier",
"logging_interval",
"central_body_LOS_radius",
]
# Check only expected categories are there that are expected
for key in cfg.keys():
Expand Down Expand Up @@ -51,7 +52,7 @@ def _check_entry_types(cfg: DotMap, major_categories: list) -> None:
"""Check that all entries in the config are of the correct type"""
# fmt: off
integer_keys = [] # noqa
float_keys = ["start_time","dt","activity_timestep","time_multiplier","logging_interval",] # noqa
float_keys = ["start_time","dt","activity_timestep","time_multiplier","logging_interval","central_body_LOS_radius"] # noqa
boolean_keys = [] # noqa
string_keys = [] # noqa
list_keys = []
Expand Down Expand Up @@ -91,7 +92,7 @@ def _check_value_ranges(cfg: DotMap, major_categories: list) -> None:

# fmt: off
positive_value_keys = ["dt","activity_timestep","time_multiplier","logging_interval",] # noqa
positive_or_zero_value_keys = ["start_time"] # noqa
positive_or_zero_value_keys = ["start_time","central_body_LOS_radius"] # noqa
# fmt: on

for key in positive_value_keys:
Expand Down