Grounds
This application demonstrates a network of ground stations given geospatial locations, minimum elevation angle constraints, and operational status.
The application contains a single class, the Environment class, which waits for a message from the manager that indicates the beginning of the simulation execution. The application publishes all of the ground station information once, at the beginning of the simulation.
Class
- class Environment(app, grounds)
Bases:
ObserverThe Environment object class inherits properties from the Observer object class in the NOS-T tools library
- app
An application containing a test-run namespace, a name and description for the app, client credentials, and simulation timing instructions
- Type:
ManagedApplication
- grounds
DataFrame of ground station information including groundId (int), latitude-longitude location (
GeographicPosition), min_elevation (float) angle constraints, and operational status (bool)- Type:
DataFrame
- Environment.on_change(source, property_name, old_value, new_value)
Standard on_change callback function format inherited from Observer object class
In this instance, the callback function checks when the PROPERTY_MODE switches to EXECUTING to send a
GroundLocationmessage to the PREFIX/ground/location topic:if property_name == Simulator.PROPERTY_MODE and new_value == Mode.EXECUTING: for index, ground in self.grounds.iterrows(): self.app.send_message( "location", GroundLocation( groundId=ground.groundId, latitude=ground.latitude, longitude=ground.longitude, elevAngle=ground.elevAngle, operational=ground.operational, ).json(), )
Schema
Schema are implemented using the pydantic library. The following schema define consistent message structures between this application and other observer applications:
- pydantic settings GroundLocation
Bases:
BaseModelMessage schema object class with properties inherited from the pydantic library’s BaseModel
Standardized message for ground station information includes:
Show JSON schema
{ "title": "GroundLocation", "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized message for ground station information includes:", "type": "object", "properties": { "groundId": { "title": "Groundid", "description": "Unique ground station identifier.", "type": "integer" }, "latitude": { "title": "Latitude", "description": "Latitude (deg) of ground station.", "minimum": -90, "maximum": 90, "type": "number" }, "longitude": { "title": "Longitude", "description": "Longitude (deg) of ground station.", "minimum": -180, "maximum": 180, "type": "number" }, "elevAngle": { "title": "Elevangle", "description": "Minimum elevation angle (deg) for satellite-ground communications", "type": "number" }, "operational": { "title": "Operational", "description": "True, if this ground station is operational.", "default": true, "type": "boolean" } }, "required": [ "groundId", "latitude", "longitude", "elevAngle" ] }
- Fields:
groundId (int)latitude (float)longitude (float)elevAngle (float)operational (bool)
- field groundId: int [Required]
Unique ground station identifier.
- field latitude: float [Required]
Latitude (deg) of ground station.
- Constraints:
minimum = -90
maximum = 90
- field longitude: float [Required]
Longitude (deg) of ground station.
- Constraints:
minimum = -180
maximum = 180
- field elevAngle: float [Required]
Minimum elevation angle (deg) for satellite-ground communications
- field operational: bool = True
True, if this ground station is operational.
Startup Script
The following code demonstrates how the ground application is started up and how the Environment Observer object class is initialized and added to the simulator:
# Note that these are loaded from a .env file in current working directory
credentials = dotenv_values(".env")
HOST, PORT = credentials["HOST"], int(credentials["PORT"])
CERTIFICATE, KEY = credentials["CERTIFICATE"], credentials["KEY"]
# set the client credentials
config = ConnectionConfig(HOST, PORT, CERTIFICATE, KEY)
# create the managed application
app = ManagedApplication("ground")
# add the environment observer to monitor simulation for switch to EXECUTING mode
app.simulator.add_observer(Environment(app, GROUND))
# add a shutdown observer to shut down after a single test case
app.simulator.add_observer(ShutDownObserver(app))
# start up the application on PREFIX, publish time status every 10 seconds of wallclock time
app.start_up(
PREFIX,
config,
True,
time_status_step=timedelta(seconds=10) * SCALE,
time_status_init=datetime(2020, 1, 1, 7, 20, tzinfo=timezone.utc),
time_step=timedelta(seconds=1) * SCALE,
)
while True:
pass