.. _groundLocation:
Module: groundLocation
======================
Executive Summary
-----------------
This module allows the user to specify a single celestial-body fixed ground location :math:`L`.
Reading in the planet's ephemeris state the position of :math:`L` relative to the planet origin and
the inertial frame are evaluated at output as a message.
Further, one or more spacecraft states can be added to this module to compute the spacecraft position
relative to the ground location :math:`L`. The associated output access output message contains the relative
position vector in terms the spherical coordinates range, azimuth and elevation angle, as well as in terms of
South-East-Zenith (SEZ) coordinates. Finally, the velocity of the spacecraft as seen by the :math:`L` location
is provided in terms of range, azimuth, elevation, south east and zenith rates. Finally, this access message
has a integer variable indicating if the spacecraft is above a minimum elevation angle of the :math:`L` SEC frame.
Module Assumptions and Limitations
----------------------------------
This module assumes that the location is affixed to a spherical body with a constant radius.
Elevation constraints are computed assuming
a conical field of view around the normal vector from the body's surface at the location.
Message Connection Descriptions
-------------------------------
The following table lists all the module input and output messages. The module msg variable name is set by the
user from python. The msg type contains a link to the message structure definition, while the description
provides information on what this message is used for.
.. list-table:: Module I/O Messages
:widths: 25 25 50
:header-rows: 1
* - Msg Variable Name
- Msg Type
- Description
* - planetInMsg
- :ref:`SpicePlanetStateMsgPayload`
- (optional) planet state input message. Default is a zero state for the planet.
* - scStateInMsgs
- :ref:`SCStatesMsgPayload`
- vector of sc state input messages. These are set through ``addSpacecraftToModel()``
* - currentGroundStateOutMsg
- :ref:`GroundStateMsgPayload`
- ground location output message
* - accessOutMsgs
- :ref:`AccessMsgPayload`
- vector of ground location access messages
Detailed Module Description
---------------------------
The ``groundLocation`` module handles the following behavior:
#. Reads in the planet's states using the ``planetInMsg`` input message
#. Conversion of latitude, longitude, altitude coordinates to planet-centered, planet-fixed coordinates
#. Conversion of relative position vector in SEZ range, azimuth, elevation, south, east and zenith coordinates
#. Determine the :math:`L` relative spacecraft velocity as range, azimuth, elevation, south,
east and zenith coordinate rates
#. Computation of spacecraft visibility (i.e. access) considering range and ground location field-of-view constraints
#. Support for multiple spacecraft given one groundLocation instance
Determining States
~~~~~~~~~~~~~~~~~~
The position of the spacecraft in the SEZ frame, relative to the ground station, is parameterized
by the cartesian coordinates:
.. math:: \mathbf{r}_{B/L} = x\hat{S} + y\hat{E} + z\hat{Z}
:label: eq:SEZ_coords:1
The cartesian coordinates are converted to spherical coordinates, centered at the ground station position,
which give the range (:math:`\rho`), azimuth(:math:`Az`), and elevation(:math:`El`).
.. math:: \rho = \sqrt{x^2 + y^2 + z^2}
:label: eq:rho:2
.. math:: Az = \tan{\frac{y}{x}}
:label: eq:az:3
.. math:: El = \tan{\frac{z}{\sqrt{x^2+y^2}}}
:label: eq:el:4
.. _glAzElSketch:
.. figure:: /../../src/simulation/environment/groundLocation/_Documentation/Images/AzEl_diagram/AzEl_sketch.jpg
:align: center
Figure 1: Diagram of the Azimuth and Elevation, in the South-East-Zenith frame
The spherical coordinate rates are computed by differentiating the range, azimuth, and elevation with respect to the rotating SEZ frame.
.. math:: \dot{\rho} = \frac{{}^L\text{d}}{\text{d}t} \rho = \frac{x\dot{x}+y\dot{y}+z\dot{z}}{\sqrt{x^2 + y^2 + z^2}}
:label: eq:SEZ_rhoDot:5
.. math:: \dot{Az} = \frac{{}^L\text{d}}{\text{d}t} Az = \frac{1}{1+\frac{y^2}{x^2}} \bigg( \frac{y\dot{x}-x\dot{y}}{x^2} \bigg)
:label: eq:SEZ_AzDot:6
.. math:: \dot{El} = \frac{{}^L\text{d}}{\text{d}t} El = \frac{1}{1+\frac{z^2}{x^2+y^2}} \bigg( \frac{\dot{z}}{\sqrt{x^2+y^2}} - \frac{z(x\dot{x}+y\dot{y})}{(x^2+y^2)^{3/2}} \bigg)
:label: eq:SEZ_ElDot:7
User Guide
----------
To use this module, instantiate the class and provide it with a body-fixed location (in either lat/long/altitude,
via the specifyLocation method, or in
planet-centered planet-fixed coordinates directly via the ``r_LP_P_Init`` attribute) and a planet position/attitude
message (i.e., an instance of :ref:`SpicePlanetStateMsgPayload`);
to compute access, at least one :ref:`SCStatesMsgPayload` message must be added to the module using the ``addSpacecraftToModel()`` method.
The first spacecraft is 0, the second is 1, and so on.
A new instance of groundLocation, alongside necessary user-supplied parameters, can be created by calling:
.. code-block:: python
groundTarget = groundLocation.GroundLocation()
groundTarget.ModelTag = "groundTarget"
groundTarget.planetRadius = orbitalMotion.REQ_EARTH * 1000.
groundTarget.maximumRange = 100e3 # Sets maximum range for visibility in meters
groundTarget.minimumElevation = np.radians(10.) # Sets necessary minimum elevation for visibility to 10 deg in radians
groundTarget.specifyLocation(np.radians(0.), np.radians(0.), 0.) # Sets location in latitude, longitude, altitude coordinates
scSim.AddModelToTask(simTaskName, groundTarget)
The ``planetRadius`` variable is optional and defaults to Earth's radius. Instead of specifying the ground location
through the ``specifyLocation()`` method, you can also set the module variable ``r_LP_P_Init`` directly.
The ``maximumRange`` variable is optional and defaults to -1. This means by default no maximum range is considered. Set it to a positive value to have ``hasAccess`` output message variable depend on range.
A groundLocation can be affixed to a specific planet by setting its ``planetInMsg`` input message:
.. code-block:: python
groundTarget.planetInMsg.subscribeTo(planetMsg)
Spacecraft can be added to the model by calling:
.. code-block:: python
groundTarget.addSpacecraftToModel(sc1.scStateOutMsg)
groundTarget.addSpacecraftToModel(sc2.scStateOutMsg)
# log code
dataLog0 = groundTarget.currentGroundStateOutMsg.recorder()
dataLog1 = groundTarget.accessOutMsgs[0].recorder()
dataLog2 = groundTarget.accessOutMsgs[1].recorder()
----
.. autodoxygenfile:: groundLocation.h
:project: groundLocation