@@ -1256,6 +1256,65 @@ def setup_conjunctions(self, conjunction_radius: float, **kwargs) -> None:
12561256 )
12571257
12581258
1259+ class MaxRangeDynModel (BasicDynamicsModel ):
1260+ """For evaluating a maximum range limitation between satellites."""
1261+
1262+ def __init__ (self , * args , ** kwargs ) -> None :
1263+ """Model that checks for maximum range violations between satellites.
1264+
1265+ The simulation is terminated at the time of separation and a range_valid failure is reported.
1266+ """
1267+ super ().__init__ (* args , ** kwargs )
1268+ self .out_of_ranges = []
1269+
1270+ def _setup_dynamics_objects (self , ** kwargs ) -> None :
1271+ super ()._setup_dynamics_objects (** kwargs )
1272+ self .setup_range (** kwargs )
1273+
1274+ @aliveness_checker
1275+ def range_valid (self ) -> bool :
1276+ """Check if conjunction has not occurred."""
1277+ return len (self .out_of_ranges ) == 0
1278+
1279+ @default_args (max_range_radius = 5000 , chief_name = None )
1280+ def setup_range (self , max_range_radius : float , chief_name : str , ** kwargs ) -> None :
1281+ """Set up maximum distance checking relative to a chief satellite.
1282+
1283+ Args:
1284+ max_range_radius: [m] Maximum allowed range from the chief satellite.
1285+ chief_name: Chief satellite to check range against.
1286+ kwargs: Passed to other setup functions.
1287+ """
1288+ self .max_range_radius = max_range_radius
1289+ self .chief_name = chief_name
1290+
1291+ if self .chief_name is None :
1292+ self .logger .warning (
1293+ "No chief satellite specified for maximum range checking. "
1294+ "Range checking is disabled."
1295+ )
1296+ return
1297+
1298+ self .simulator .createNewEvent (
1299+ valid_func_name (f"range_{ self .satellite .name } _{ self .chief_name } " ),
1300+ macros .sec2nano (self .simulator .sim_rate ),
1301+ True ,
1302+ [
1303+ f"np.linalg.norm(np.array({ self .satellite ._satellite_command } .dynamics.r_BN_N)"
1304+ + f"- np.array(self.get_satellite('{ self .chief_name } ').dynamics.r_BN_N))"
1305+ + " >= "
1306+ + f"{ self .satellite ._satellite_command } .dynamics.max_range_radius"
1307+ ],
1308+ [
1309+ self .satellite ._info_command (
1310+ f"Exceeded maximum range of { max_range_radius } m from { self .chief_name } "
1311+ ),
1312+ f"{ self .satellite ._satellite_command } .dynamics.out_of_ranges.append(self.get_satellite('{ self .chief_name } '))" ,
1313+ ],
1314+ terminal = True ,
1315+ )
1316+
1317+
12591318__doc_title__ = "Dynamics Sims"
12601319__all__ = [
12611320 "DynamicsModel" ,
@@ -1265,5 +1324,6 @@ def setup_conjunctions(self, conjunction_radius: float, **kwargs) -> None:
12651324 "ContinuousImagingDynModel" ,
12661325 "GroundStationDynModel" ,
12671326 "ConjunctionDynModel" ,
1327+ "MaxRangeDynModel" ,
12681328 "FullFeaturedDynModel" ,
12691329]
0 commit comments