Grounds

This application demonstrates a network of ground stations given geospatial locations, minimum elevation angle constraints, and operational status.

The application contains a GroundNetwork (Observer) object class to track the state of each constituent ground station, as well as the LinkStartObserver and LinkEndObserver object classes that monitor Acquisition of Signal (AOS) and Loss of Signal (LOS) events, respectively.


GroundNetwork

class GroundNetwork(app, grounds)

Bases: Observable, Observer

The GroundNetwork 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

GroundNetwork.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 GroundLocation message to the PREFIX/ground/location topic.

GroundNetwork.on_ready(ch, method, properties, body)

Callback function for subscribed messages on the PREFIX/constellation/ready topic.

For each message received, appends a satellite and its specs to internal lists.

Parameters:
  • client (MQTT Client) – Client that connects application to the event broker using the MQTT protocol. Includes user credentials, tls certificates, and host server-port information.

  • userdata – User defined data of any type (not currently used).

  • message (message) – Contains topic the client subscribed to and payload message content as attributes.

GroundNetwork.all_ready(ch, method, properties, body)

Callback function for subscribed messages on the PREFIX/constellation/allReady topic.

This is a simple trigger that the list of constituent satellites have been finalized and appended to lists.

Parameters:
  • client (MQTT Client) – Client that connects application to the event broker using the MQTT protocol. Includes user credentials, tls certificates, and host server-port information.

  • userdata – User defined data of any type (not currently used).

  • message (message) – Contains topic the client subscribed to and payload message content as attributes.

GroundNetwork.on_commRange(ch, method, properties, body)

Callback function triggered by every SatelliteState message received on the PREFIX/constellation/location topic.

Checks for changes in switch states and records timestamps of state transitions.

Parameters:
  • client (MQTT Client) – Client that connects application to the event broker using the MQTT protocol. Includes user credentials, tls certificates, and host server-port information.

  • userdata – User defined data of any type (not currently used).

  • message (message) – Contains topic the client subscribed to and payload message content as attributes.

GroundNetwork.on_outage(ch, method, properties, body)

Callback function triggered by every OutageReport message received on the PREFIX/outages/report topic.

Appends a new outage dictionary to a list of outage dictionaries. Used to indicate which ground station has become inoperable and the expected outage duration.

Parameters:
  • client (MQTT Client) – Client that connects application to the event broker using the MQTT protocol. Includes user credentials, tls certificates, and host server-port information.

  • userdata – User defined data of any type (not currently used).

  • message (message) – Contains topic the client subscribed to and payload message content as attributes.

GroundNetwork.on_restore(ch, method, properties, body)

Callback function triggered by every OutageRestore message received on the PREFIX/outages/restore topic.

Notifies observers of restored service at a previously inoperable ground station.

Parameters:
  • client (MQTT Client) – Client that connects application to the event broker using the MQTT protocol. Includes user credentials, tls certificates, and host server-port information.

  • userdata – User defined data of any type (not currently used).

  • message (message) – Contains topic the client subscribed to and payload message content as attributes.

GroundNetwork.fixedCost(ch, method, properties, body)

Callback function triggered by every LinkCharge message sent to the PREFIX/constellation/linkCharge topic.

Messages only apply to satellites operating under fixed contracts. These messages are intended to create a continuous cost curve for the visualizations.

Parameters:
  • client (MQTT Client) – Client that connects application to the event broker using the MQTT protocol. Includes user credentials, tls certificates, and host server-port information.

  • userdata – User defined data of any type (not currently used).

  • message (message) – Contains topic the client subscribed to and payload message content as attributes.


Event Observers

class LinkStartObserver(app)

Bases: Observer

This object class inherits properties from the Observer object class from the observer template in the NOS-T tools library.

Parameters:

app (ManagedApplication) – An application containing a test-run namespace, a name and description for the app, client credentials, and simulation timing instructions.

LinkStartObserver.on_change(source, property_name, old_value, new_value)

Standard on_change callback function format inherited from Observer object class in NOS-T tools library.

In this instance, the callback function checks for notification of the PROPERTY_IN_RANGE and publishes LinkStart message to PREFIX/ground/linkStart topic.


class LinkEndObserver(app)

Bases: Observer

This object class inherits properties from the Observer object class from the observer template in the NOS-T tools library.

Parameters:

app (ManagedApplication) – An application containing a test-run namespace, a name and description for the app, client credentials, and simulation timing instructions.

LinkEndObserver.on_change(source, property_name, old_value, new_value)

Standard on_change callback function format inherited from Observer object class in NOS-T tools library

In this instance, the callback function checks for notification of the PROPERTY_OUT_OF_RANGE and publishes LinkCharge message to PREFIX/ground/linkCharge topic.


Schema

Schema are implemented using the pydantic library. The following schema define consistent message structures between this application and other observer applications:

pydantic settings SatelliteReady

Bases: BaseModel

Message schema object class with properties inherited from the pydantic library’s BaseModel

Standardized initializing message for each satellite in the constellation includes:

Show JSON schema
{
   "title": "SatelliteReady",
   "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized initializing message for each satellite in the constellation includes: ",
   "type": "object",
   "properties": {
      "id": {
         "description": "Unique satellite identifier",
         "title": "Id",
         "type": "integer"
      },
      "name": {
         "description": "Satellite name for labeling",
         "title": "Name",
         "type": "string"
      },
      "ssr_capacity": {
         "description": "Capacity of onboard Solid State Recorder in Gigabytes",
         "title": "Ssr Capacity",
         "type": "number"
      }
   },
   "required": [
      "id",
      "name",
      "ssr_capacity"
   ]
}

Fields:
  • id (int)

  • name (str)

  • ssr_capacity (float)

field id: int [Required]

Unique satellite identifier

field name: str [Required]

Satellite name for labeling

field ssr_capacity: float [Required]

Capacity of onboard Solid State Recorder in Gigabytes


pydantic settings SatelliteState

Bases: BaseModel

Message schema object class with properties inherited from the pydantic library’s BaseModel

Standardized satellite status message includes:

Show JSON schema
{
   "title": "SatelliteState",
   "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized satellite status message includes: \n    ",
   "type": "object",
   "properties": {
      "id": {
         "description": "Unique satellite identifier",
         "title": "Id",
         "type": "integer"
      },
      "name": {
         "description": "Satellite name for labeling",
         "title": "Name",
         "type": "string"
      },
      "latitude": {
         "description": "Latitude (deg) of satellite subpoint location.",
         "maximum": 90,
         "minimum": -90,
         "title": "Latitude",
         "type": "number"
      },
      "longitude": {
         "description": "Longitude (deg) of satellite subpoint location.",
         "maximum": 180,
         "minimum": -180,
         "title": "Longitude",
         "type": "number"
      },
      "altitude": {
         "description": "Altitude (meters) of satellite above sea level",
         "title": "Altitude",
         "type": "number"
      },
      "capacity_used": {
         "description": "GB of solid state recorder capacity used",
         "title": "Capacity Used",
         "type": "number"
      },
      "commRange": {
         "default": false,
         "description": "Boolean for if satellite is in ground stations view",
         "title": "Commrange",
         "type": "boolean"
      },
      "groundId": {
         "anyOf": [
            {
               "type": "integer"
            },
            {
               "type": "null"
            }
         ],
         "description": "Ground Station id in view (None if not in view)",
         "title": "Groundid"
      },
      "totalLinkCount": {
         "anyOf": [
            {
               "type": "integer"
            },
            {
               "type": "null"
            }
         ],
         "description": "Running count of downlink opportunity per satellite",
         "title": "Totallinkcount"
      },
      "cumulativeCostBySat": {
         "description": "Cumulative cost of downlinks and/or fixed cost contracts per satellite",
         "title": "Cumulativecostbysat",
         "type": "number"
      },
      "time": {
         "description": "Time in satellite reference frame",
         "format": "date-time",
         "title": "Time",
         "type": "string"
      }
   },
   "required": [
      "id",
      "name",
      "latitude",
      "longitude",
      "altitude",
      "capacity_used",
      "groundId",
      "totalLinkCount",
      "cumulativeCostBySat",
      "time"
   ]
}

Fields:
  • id (int)

  • name (str)

  • latitude (float)

  • longitude (float)

  • altitude (float)

  • capacity_used (float)

  • commRange (bool)

  • groundId (int | None)

  • totalLinkCount (int | None)

  • cumulativeCostBySat (float)

  • time (datetime.datetime)

field id: int [Required]

Unique satellite identifier

field name: str [Required]

Satellite name for labeling

field latitude: float [Required]

Latitude (deg) of satellite subpoint location.

Constraints:
  • ge = -90

  • le = 90

field longitude: float [Required]

Longitude (deg) of satellite subpoint location.

Constraints:
  • ge = -180

  • le = 180

field altitude: float [Required]

Altitude (meters) of satellite above sea level

field capacity_used: float [Required]

GB of solid state recorder capacity used

field commRange: bool = False

Boolean for if satellite is in ground stations view

field groundId: int | None [Required]

Ground Station id in view (None if not in view)

field totalLinkCount: int | None [Required]

Running count of downlink opportunity per satellite

field cumulativeCostBySat: float [Required]

Cumulative cost of downlinks and/or fixed cost contracts per satellite

field time: datetime [Required]

Time in satellite reference frame


pydantic settings GroundLocation

Bases: BaseModel

Message 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": {
         "description": "Unique ground station identifier",
         "title": "Groundid",
         "type": "integer"
      },
      "latitude": {
         "description": "Latitude (deg) of ground station.",
         "maximum": 90,
         "minimum": -90,
         "title": "Latitude",
         "type": "number"
      },
      "longitude": {
         "description": "Longitude (deg) of ground station.",
         "maximum": 180,
         "minimum": -180,
         "title": "Longitude",
         "type": "number"
      },
      "elevAngle": {
         "description": "Minimum elevation angle (deg) for satellite-ground communications",
         "title": "Elevangle",
         "type": "number"
      },
      "operational": {
         "default": true,
         "description": "True, if this ground station is operational",
         "title": "Operational",
         "type": "boolean"
      },
      "downlinkRate": {
         "description": "Downlink rate for this ground station in Megabytes per second",
         "title": "Downlinkrate",
         "type": "number"
      },
      "costPerSecond": {
         "description": "Cost in $ per second for downlinks",
         "title": "Costpersecond",
         "type": "number"
      },
      "costMode": {
         "default": "discrete",
         "description": "Could be a boolean, options are discrete or fixed, default to discrete",
         "title": "Costmode",
         "type": "string"
      }
   },
   "required": [
      "groundId",
      "latitude",
      "longitude",
      "elevAngle",
      "downlinkRate",
      "costPerSecond"
   ]
}

Fields:
  • groundId (int)

  • latitude (float)

  • longitude (float)

  • elevAngle (float)

  • operational (bool)

  • downlinkRate (float)

  • costPerSecond (float)

  • costMode (str)

field groundId: int [Required]

Unique ground station identifier

field latitude: float [Required]

Latitude (deg) of ground station.

Constraints:
  • ge = -90

  • le = 90

field longitude: float [Required]

Longitude (deg) of ground station.

Constraints:
  • ge = -180

  • le = 180

field elevAngle: float [Required]

Minimum elevation angle (deg) for satellite-ground communications

field operational: bool = True

True, if this ground station is operational

field downlinkRate: float [Required]

Downlink rate for this ground station in Megabytes per second

field costPerSecond: float [Required]

Cost in $ per second for downlinks

field costMode: str = 'discrete'

Could be a boolean, options are discrete or fixed, default to discrete


pydantic settings LinkStart

Bases: BaseModel

Message schema object class with properties inherited from the pydantic library’s BaseModel

Standardized message indicating the beginning of a downlink opportunity includes:

Show JSON schema
{
   "title": "LinkStart",
   "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized message indicating the beginning of a downlink opportunity includes:",
   "type": "object",
   "properties": {
      "groundId": {
         "description": "Unique ground station identifier",
         "title": "Groundid",
         "type": "integer"
      },
      "satId": {
         "description": "Unique satellite identifier that performed the downlink",
         "title": "Satid",
         "type": "integer"
      },
      "satName": {
         "description": "Name of satellite that performed the downlink",
         "title": "Satname",
         "type": "string"
      },
      "linkId": {
         "description": "Unique downlink counter for the specific spacecraft that downlinked",
         "title": "Linkid",
         "type": "integer"
      },
      "start": {
         "description": "Start time in ground network reference frame",
         "format": "date-time",
         "title": "Start",
         "type": "string"
      },
      "data": {
         "description": "Current amount of data on-board the satellite that needs to be offloaded",
         "title": "Data",
         "type": "number"
      }
   },
   "required": [
      "groundId",
      "satId",
      "satName",
      "linkId",
      "start",
      "data"
   ]
}

Fields:
  • groundId (int)

  • satId (int)

  • satName (str)

  • linkId (int)

  • start (datetime.datetime)

  • data (float)

field groundId: int [Required]

Unique ground station identifier

field satId: int [Required]

Unique satellite identifier that performed the downlink

field satName: str [Required]

Name of satellite that performed the downlink

field linkId: int [Required]

Unique downlink counter for the specific spacecraft that downlinked

field start: datetime [Required]

Start time in ground network reference frame

field data: float [Required]

Current amount of data on-board the satellite that needs to be offloaded


pydantic settings LinkCharge

Bases: BaseModel

Message schema object class with properties inherited from the pydantic library’s BaseModel

Standardized message indicating the end of a downlink opportunity and updating cost ledgers includes:

Show JSON schema
{
   "title": "LinkCharge",
   "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized message indicating the end of a downlink opportunity and updating cost ledgers includes:",
   "type": "object",
   "properties": {
      "groundId": {
         "description": "Unique ground station identifier",
         "title": "Groundid",
         "type": "integer"
      },
      "satId": {
         "description": "Unique satellite identifier that performed the downlink",
         "title": "Satid",
         "type": "integer"
      },
      "satName": {
         "description": "Name of satellite that performed the downlink",
         "title": "Satname",
         "type": "string"
      },
      "linkId": {
         "description": "Unique downlink counter for the specific spacecraft that downlinked",
         "title": "Linkid",
         "type": "integer"
      },
      "end": {
         "description": "Time stamp for end of downlink when charge is sent",
         "format": "date-time",
         "title": "End",
         "type": "string"
      },
      "duration": {
         "description": "Time duration of satellite in view for this downlink (s)",
         "title": "Duration",
         "type": "number"
      },
      "dataOffload": {
         "description": "Amount of data offloaded based on linear downlink rates unique to each ground station (GB)",
         "title": "Dataoffload",
         "type": "number"
      },
      "downlinkCost": {
         "description": "Cost of data downlink based on per-second cost rates unique to each ground station",
         "title": "Downlinkcost",
         "type": "number"
      },
      "cumulativeCostBySat": {
         "description": "Dictionary of running totals for downlink costs per satellite",
         "title": "Cumulativecostbysat",
         "type": "number"
      },
      "cumulativeCosts": {
         "description": "Running total of ALL downlink costs for the entirety of the Test Case",
         "title": "Cumulativecosts",
         "type": "number"
      }
   },
   "required": [
      "groundId",
      "satId",
      "satName",
      "linkId",
      "end",
      "duration",
      "dataOffload",
      "downlinkCost",
      "cumulativeCostBySat",
      "cumulativeCosts"
   ]
}

Fields:
  • groundId (int)

  • satId (int)

  • satName (str)

  • linkId (int)

  • end (datetime.datetime)

  • duration (float)

  • dataOffload (float)

  • downlinkCost (float)

  • cumulativeCostBySat (float)

  • cumulativeCosts (float)

field groundId: int [Required]

Unique ground station identifier

field satId: int [Required]

Unique satellite identifier that performed the downlink

field satName: str [Required]

Name of satellite that performed the downlink

field linkId: int [Required]

Unique downlink counter for the specific spacecraft that downlinked

field end: datetime [Required]

Time stamp for end of downlink when charge is sent

field duration: float [Required]

Time duration of satellite in view for this downlink (s)

field dataOffload: float [Required]

Amount of data offloaded based on linear downlink rates unique to each ground station (GB)

field downlinkCost: float [Required]

Cost of data downlink based on per-second cost rates unique to each ground station

field cumulativeCostBySat: float [Required]

Dictionary of running totals for downlink costs per satellite

field cumulativeCosts: float [Required]

Running total of ALL downlink costs for the entirety of the Test Case


pydantic settings OutageReport

Bases: BaseModel

Message schema object class with properties inherited from the pydantic library’s BaseModel

Standardized message indicating the beginning of an outage at a ground station includes:

Show JSON schema
{
   "title": "OutageReport",
   "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized message indicating the beginning of an outage at a ground station includes:",
   "type": "object",
   "properties": {
      "groundId": {
         "description": "Unique ground station identifier experiencing outage",
         "title": "Groundid",
         "type": "integer"
      },
      "outageStart": {
         "description": "Initial time of outage report",
         "format": "date-time",
         "title": "Outagestart",
         "type": "string"
      },
      "outageDuration": {
         "description": "Duration of the reported outage",
         "format": "duration",
         "title": "Outageduration",
         "type": "string"
      },
      "outageEnd": {
         "description": "outageStart + outageDuration",
         "format": "date-time",
         "title": "Outageend",
         "type": "string"
      }
   },
   "required": [
      "groundId",
      "outageStart",
      "outageDuration",
      "outageEnd"
   ]
}

Fields:
  • groundId (int)

  • outageStart (datetime.datetime)

  • outageDuration (datetime.timedelta)

  • outageEnd (datetime.datetime)

field groundId: int [Required]

Unique ground station identifier experiencing outage

field outageStart: datetime [Required]

Initial time of outage report

field outageDuration: timedelta [Required]

Duration of the reported outage

field outageEnd: datetime [Required]

outageStart + outageDuration


pydantic settings OutageRestore

Bases: BaseModel

Message schema object class with properties inherited from the pydantic library’s BaseModel

Standardized message indicating the end of an outage with restored service at a ground station includes:

Show JSON schema
{
   "title": "OutageRestore",
   "description": "*Message schema object class with properties inherited from the pydantic library's BaseModel*\n\nStandardized message indicating the end of an outage with restored service at a ground station includes:",
   "type": "object",
   "properties": {
      "groundId": {
         "description": "Unique ground station identifier",
         "title": "Groundid",
         "type": "integer"
      },
      "outageEnd": {
         "description": "outageStart + outageDuration",
         "format": "date-time",
         "title": "Outageend",
         "type": "string"
      }
   },
   "required": [
      "groundId",
      "outageEnd"
   ]
}

Fields:
  • groundId (int)

  • outageEnd (datetime.datetime)

field groundId: int [Required]

Unique ground station identifier

field outageEnd: datetime [Required]

outageStart + outageDuration