-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathspacecraft_actor.py
166 lines (127 loc) · 4.77 KB
/
spacecraft_actor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
from loguru import logger
import pykep as pk
from paseos.actors.base_actor import BaseActor
from paseos.power import discharge_model
from paseos.power import charge_model
class SpacecraftActor(BaseActor):
"""This class models a spacecraft actor which in addition to pos,
velocity also has additional constraints such as power/battery."""
# Power-related properties
_power_device_type = None
_battery_level_in_Ws = None
_max_battery_level_in_Ws = None
_charging_rate_in_W = None
# Actor's mass in kg
_mass = None
_thermal_model = None
_radiation_model = None
# If radiation randomly restarted the device
_was_interrupted = False
# If radiation permanently killed this device
_is_dead = False
def __init__(
self,
name: str,
epoch: pk.epoch,
) -> None:
"""Constructor for a spacecraft actor
Args:
name (str): Name of this actor
epoch (pykep.epoch): Epoch at this pos
"""
logger.trace("Instantiating SpacecraftActor.")
super().__init__(name, epoch)
def set_is_dead(self):
"""Sets this device to "is_dead=True" indicating permanent damage."""
self._is_dead = True
def set_was_interrupted(self):
"""Sets this device to "was_interrupted=True" indicating current activities were interrupted."""
self._was_interrupted = True
@property
def was_interrupted(self) -> bool:
"""Returns whether the actor was interrupted in its activity.
Returns:
bool: True if device is interrupted.
"""
return self._was_interrupted
@property
def is_dead(self) -> bool:
"""Returns whether the device experienced fatal radiation failure.
Returns:
bool: True if device is dead.
"""
return self._is_dead
@property
def power_device_type(self):
"""Get the power device type
Returns:
PowerDeviceType: Type of power device.
"""
return self._power_device_type
@property
def charging_rate_in_W(self):
"""Get the current charging rate.
Returns:
float: current charging rate in W.
"""
return self._charging_rate_in_W
@property
def battery_level_in_Ws(self):
"""Get the current battery level.
Returns:
float: current battery level in wattseconds.
"""
return self._battery_level_in_Ws
@property
def mass(self) -> float:
"""Returns actor's mass in kg.
Returns:
float: Mass
"""
return self._mass
@property
def temperature_in_K(self) -> float:
"""Returns the current temperature of the actor in K.
Returns:
float: Actor temperature in Kelvin.
"""
return self._thermal_model.temperature_in_K
@property
def temperature_in_C(self) -> float:
"""Returns the current temperature of the actor in C.
Returns:
float: Actor temperature in Celsius.
"""
return self._thermal_model.temperature_in_K - 273.15
@property
def state_of_charge(self):
"""Get the current battery level as ratio of maximum.
Returns:
float: current battery level ratio in [0,1].
"""
return self._battery_level_in_Ws / self._max_battery_level_in_Ws
def discharge(self, consumption_rate_in_W: float, duration_in_s: float):
"""Discharge battery depending on power consumption.
Args:
consumption_rate_in_W (float): Consumption rate of the activity in Watt
duration_in_s (float): How long the activity is performed in seconds
"""
assert duration_in_s > 0, "Duration has to be positive"
assert consumption_rate_in_W >= 0, "Power consumption rate has to be positive"
power_consumption = consumption_rate_in_W * duration_in_s
logger.debug(f"Discharging {power_consumption}")
self = discharge_model.discharge(self, power_consumption)
logger.debug(f"New battery level is {self._battery_level_in_Ws}Ws")
def charge(self, duration_in_s: float):
"""Charges the actor from now for that period. Note that it is only
verified the actor is neither at start nor end of the period in eclipse,
thus short periods are preferable.
Args:
duration_in_s (float): How long the activity is performed in seconds
"""
logger.debug(f"Charging actor {self} for {duration_in_s}s.")
assert (
duration_in_s > 0
), "Charging interval has to be positive but t1 was less or equal t0."
self = charge_model.charge(self, duration_in_s)
logger.debug(f"New battery level is {self.battery_level_in_Ws}")