.. _platforms_model: ################### The Platforms Model ################### The ``skretrieval.platforms`` package provides support to simulate platforms such as spacecraft, aircraft, balloons and ground-based sites. Instruments are mounted on platforms at given orientations, similar to how physical instruments are bolted on to real platforms, and the platform is positioned and rotated to collect the desired set of measurements. Its goal within the ``skretrieval`` framework is to assist in the generation of the set of times, positions and look vectors given to :ref:`forwardmodel`. Users who have their own techniques for calculating positions and look vectors for the :ref:`forwardmodel` can continue using their own code or, if they wish, switch over to using the :class:`~.Platform` class. Class :class:`~.Platform` provides access to two primary aspects, #. Simulation of various platforms used in remote atmospheric sensing. #. Generation of sets of platform position and orientation using various positioning and pointing techniques. The :class:`~.Platform` class utilizes several :ref:`controlframes` and provides rotation matrices to transform between the frames. The user will typically define instrument lines of sight in the :ref:`icf`. The instrument is optionally mounted on a platform and the platform rotated in space and time to execute the desired measurement plan. Users will normally transform the instrument look vectors to the :ref:`ecef` for input to radiative transfer codes but the platform can also transform the look vector to the local geodetic control frame or platform control frame if preferred. Class :class:`~.Platform` provides a high level interface which can be used to calculate platform positions and orientations needed to simulate a set of measurements. The class, as provided out-of-the-box, provides access to a library of common techniques that that should meet most user needs but the API allows new techniques to be developed and added by users. The problem usually reduces into two parts, #. selection of an instrument positioning technique. #. selection of an instrument pointing technique. Example ======= Consider a simulation where an instrument onboard a sun-synchronous satellite at an altitude of 600 km needs to look in the limb at a tangent point at 35 km altitude over Saskatoon, Saskatchewan, located at (52.0N, -107.0E). The observation will be made at approximately 2020-07-15 15:00 UTC. The satellite is configured so the instrument is always looking at a bearing of 45 degrees from local North at the satellite location. We shall demonstrate three techniques that could be used to *solve* the problem. The three techniques are based upon significantly different algorithms but, from the user's perspective, are implemented in an almost identical manner. Option 1: llh ------------- Use the :class:`~.Platform` class with no special configuration. Set the time and position of the satellite with the :ref:`llh` positioning technique. Then configure the platform orientation with the :ref:`tangent_altitude` pointing technique using :ref:`rollcontrol_limb` roll control so it is looking at that tangent point. This will generate the required position and look vector for the given conditions. The option has the limitation that it is difficult to choose the position of the platform so the tangent point is over Saskatoon:: from skretrieval.platforms import Platform platform = Platform() utc = ['2020-07-15T15:00:00.0000000'] observer = [52.0, -107.0, 600000.0] tanpoint = [35000.0, 45.0] platform.add_measurement_set(utc, ('llh', observer), ('tangent_altitude', 'limb', tanpoint)) opticalmeasurements = platform.make_optical_geometry() If you want to print out the location of the satellite and the tangent point you can use the following snippet of code:: import sasktran as sk geo = sk.Geodetic() entry = opticalmeasurements[0] geo.from_xyz(entry.observer) obslat = geo.latitude obslng = geo.longitude obshgt = geo.altitude / 1000.0 geo.from_tangent_point(entry.observer, entry.look_vector) tanlat = geo.latitude tanlng = geo.longitude tanhgt = geo.altitude / 1000.0 print('Satellite location = ({:5.2f}N,{:6.2f}E) at a height of {:6.2f} km'.format(obslat, obslng, obshgt)) print('Tangent location = ({:5.2f}N,{:6.2f}E) at a height of {:6.2f} km'.format(tanlat, tanlng, tanhgt)) and you should get:: Satellite location = (52.00N,253.00E) at a height of 600.00 km Tangent location = (63.65N,291.78E) at a height of 35.00 km The tangent point is at 35 km as requested but it is not over Saskatoon, which is not surprising as we, perhaps erroneously, put the satellite directly over Saskatoon. To get the tangent point directly over Saskatoon you could iteratively adjust the satellite position until you find teh right locations. But there is an easier way demonstrated below in option 2. Option 2: looking_at_llh ------------------------ The second option provides a more sophisticated technique to position the satellite so the resultant tangent point will end up above Saskatoon. In this case set the time and position of the satellite are set with the :ref:`looking_at_llh` positioning technique; this technique has 5 parameters that position the satellite at the requested altitude so it will have the requested tangent altitude at the requested location with the requested bearing. It then configures the platform orientation with the :ref:`tangent_altitude` pointing technique using :ref:`rollcontrol_limb` roll control so it is looking at that tangent point:: from skretrieval.platforms import Platform platform = Platform() utc = ['2020-07-15T15:00:00.0000000'] observer = [52.0, -107.0, 35000.0, 45.0, 600000.0] tanpoint = [35000.0, 45.0] platform.add_measurement_set(utc, ('looking_at_llh', observer), ('tangent_altitude', 'limb', tanpoint)) opticalmeasurements = platform.make_optical_geometry() Examination of the location of the satellite and tangent point using the same code as in option 1 above gives:: Satellite location = (38.23N,226.13E) at a height of 600.00 km Tangent location = (52.02N,252.98E) at a height of 35.00 km Now the tangent point is above Saskatoon and the satellite has been placed at a location so it is looking toward Saskatoon at a tangent altitude of 35 km and a bearing of 45 degrees. Note that the tangent point is not "*exactly*" above Saskatoon. It is off by approx 0.02 degrees which is due to limitations in the algorithm used. Option 3: satellite ------------------- This option configures the :class:`~.Platform` class with a sun-synchronous satellite orbit propagator. the satellite is *flown* along the orbit track by providing a sequence of 100 universal times at 1 minute intervals. The position of the platform is now extracted using the :ref:`from_platform` positioning technique while the look vector is still extracted with the :ref:`tangent_altitude` pointing technique and :ref:`rollcontrol_limb` roll control. This option requires a bit more setup but allows the user to *fly* the satellite around the Earth and generate other positions and look vectors:: mjd0 = sktime.ut_to_mjd('2020-07-15T15:00:00.000000') # Define the time of the ascending node satellite = SatelliteSunSync(mjd0, # Create a sun-synchronous satellite orbittype='sgp4', period_from_altitude=600000.0, localtime_of_ascending_node_hours=2.75) platform = Platform(platform_locator=satellite) # Create a platform which can use the sun-synchronous satellite for its position utc = mjd0 + np.arange(0, 100) / 1440.0 # Get measurements every minute along the orbit starting at the ascending node. looktanalt = [(35000.0, 45)] # Look at a tangent altitude of 35 km, at a geographic bearing of 45 degrees at the satellite location. Note, the parameter set will be expanded to N measurements platform.add_measurement_set(utc, ('from_platform',), ('tangent_altitude', 'limb', looktanalt)) # Add the measurement set opticalmeasurements = platform.make_optical_geometry() This technique has the same problem as option 1 in that it is difficult to pre-configure the satellite to fly exactly over Saskatoon with the proper geometry. However, we fiddled with the local time of the ascending node of the satellite and if you look at the 38'th entry of the 100 returned ``opticalmeasurement`` values you should see that it has a tangent point close to Saskatoon:: 38 Satellite location = (38.26N,235.59E) at a height of 605.39 km 38 Tangent location = (52.09N,262.62E) at a height of 35.00 km ------------------------------------------------------------------------------------------------------------------------ Measurement Sets ================ The user must define what constitutes a set of measurements. This may be as simple as one exposure or something much more complicated such as a spatial scan of a specific atmospheric region. In our experience, we almost always break the definition of measurements sets into the following three steps, #. Define (or acquire) a set of universal times at which the measurements are made. #. Specify (or acquire) the position of the platform associated with each measurement at each universal time. #. Specify (or acquire) the pointing of the platform associated with each measurement at each universal time. Example ------- Configure a satellite to acquire a height profile of spectra over Saskatoon (52N, -107E) in the summer time from which atmospheric aerosols can be inferred over Saskatooon . **Option 1**: A simple emulator fixes a satellite ~20 degrees south of Saskatoon at 600 km looking northwards in the limb. There will be 50 measurements scanning from 0 km to 50 km all made at the same location and same time UTC (2020-06-21T18:00:00.000000) **Option 2:** A sun-synchronous satellite with an ascending node at 12:00LT will fly over Saskatoon on 2020-06-21. It will collect 50 measurements scanning from 0 to 50 km. The measurements will be one second apart. The ``skretrieval.platforms`` package can help with both of these scenarios and the user would choose which scenario they wish to model. Internal Representation ----------------------- Measurement sets are internally stored within class :class:`~.Platform` using an instance of :class:`ObservationPolicy`. This class stores a set of times, position and rotation matrices used for the measurements. This information is independent of the instrument, apart from its mounting orientation, and cannot be used by retrieval and radiative transfer codes until it is converted into a set of times, positions and instrument look vectors, such as those found in :class:`~.OpticalGeometry`. ------------------------------------------------------------------------------------------------------------------------ .. _positioning_technique: Positioning Technique ====================== *Positioning Techniques* are used to specify the position of a platform at a set of measurement times. For example, one technique may specify the position of a platform using a three element array of geodetic coordinates, :math:`(latitude, longitude, height)`, while another technique may specify the same location using a three element array of geocentric coordinates, :math:`(x,y,z)`. The user chooses which technique they wish to use, see table below. Coding up the positioning technique consists of the following steps #. Determine the number of measurements. This is driven by the number of different platform positions and orientations #. Create an array of universal times with one time for each measurement. The times can be the same or they can be different #. Create an array of platform position arrays. One array entry is created for each measurement. #. Create a tuple whose first element identifies the position technique and the second element is the array of positions. #. Pass the array of UTC times and the tuple of position technique into :meth:`~.platform.add_measurement_set` along with orientation info described below. For example:: utcarray = ['2020-09-24T12:15:36.123456', '2020-09-24T12:15:37.456123', '2020-09-24T12:15:38.654321', '2020-09-24T12:15:39.654321'] posarray = [(52, -107, 600000), (53, -107, 600001), (54, -107, 600002), (55,-107, 600003)] postechn = ('llh',posarry) . . looktechn = . . platform.add_measurement_set(utcarray, postechn, looktechn) There are three positioning techniques provided with the ``skretrieval.platforms`` package. Their values are given in the table below, =============================== ======================================================================================================== Position Technique Description =============================== ======================================================================================================== :ref:`xyz` The platform is placed at the geocentric ECEF point given by (x,y,z) :ref:`llh` The platform is placed at the geodetic ECEF location given by (latitude, longitude, height) :ref:`looking_at_llh` The platform is placed so it is looking at a given location with a given geographic bearing. :ref:`from_platform` The platform is placed at the position of a real instrument or platform simulator using :class:`~.PlatformLocation`. =============================== ======================================================================================================== The last entry, :ref:`from_platform`, allows users to fetch the platform position at a given universal time from an attached :class:`~.PlatformLocation` object. This technique is used to model various satellite trajectories, both real and simulated, and is useful when users wish to simulate measurements as a satellite, aircraft or balloon, moves along its trajectory. ------------------------------------------------------------------------------------------------------------------------ .. _xyz: xyz --- The ``xyz`` positioning technique places the platform at the *N* specified geocentric locations for each measurement in the parameter array. .. function:: ( 'xyz', parameters ) ``parameters`` is an N element array of three element arrays, ``[array[3], array[3], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,3). All values are expressed in meters in the :ref:`ecef`. :param float [0]: **x** component of the platform position. :param float [1]: **y** component of the platform position. :param float [2]: **z** component of the platform position. Example:: from skretrieval.platforms import Platform def make_geometry(): platform = Platform() utc = ['2020-09-24T12:15:36.123456', '2020-09-24T12:15:37.456123', '2020-09-24T12:15:38.654321', '2020-09-24T12:15:39.654321'] pos = [(7223456.0,1023456.0, 1423456.0), (7523456.0,923456.0, 1523456.0) (7223456.0,1023456.0, 1423456.0), (7523456.0,923456.0, 1523456.0)] look = [(35000, 10), (27000, 5), (24000, 0, 0), (21000, -5, 0)] platform.add_measurement_set( utc, ('xyz', pos), ('tangent_altitude', 'limb', look) ) obspolicy = platform.make_observation_policy() ------------------------------------------------------------------------------------------------------------------------ .. _llh: llh --- The platform is placed at the geodetic location given by the three element tuple, (latitiude, longitude, height), where latitude and longitude are specified in degrees and height is specified in meters above sea-level. .. function:: ( 'llh', parameters ) ``parameters`` is an N element array of three element arrays, ``[array[3], array[3], ...]``. It is coerced into a numpy array of dimension (N,3). :param float [0]: **Latitude**. The geodetic latitude of the platform position in degrees. :param float [1]: **Longitude**. The geodetic longitude of the platform position in degrees. positive East. :param float [2]: **Height**. The height of the platform above sea-level in meters. Example:: from skretrieval.platforms import Platform def make_geometry(): platform = Platform() utc = ['2020-09-24T12:15:36.123456', '2020-09-24T12:15:37.456123', '2020-09-24T12:15:38.654321', '2020-09-24T12:15:39.654321'] pos = [(52, -107, 600000), (53, -107, 600001), (54, -107, 600002), (55,-107, 600003)] look = [(35000, 10, 0), (27000, 5, 0), (24000, 0, 0), (21000, -5, 0)] platform.add_measurement_set( utc, ('llh', pos), ('tangent_altitude', 'limb', look) ) platform.make_complete_measurement_set() ------------------------------------------------------------------------------------------------------------------------ .. _looking_at_llh: looking_at_llh -------------- The platform is placed at the location and height that allows it to view the given target tangent point along the given geographic bearing. .. function:: ( 'looking_at_llh', parameters ) ``parameters`` is an N element array of five element arrays, ``[array[5], array[5], ...]``. It is coerced into a numpy array of dimension (N,5). :param float [0]: **Tangent Latitude**. The latitude of the tangent location :param float [1]: **Tangent Longitude**. The longitude of the tangent location :param float [2]: **Tangent Altitude**. The height of the tangent above sea-level in meters. :param float [3]: **Geographic Bearing**. The geographic bearing in degrees of the target from the observer's location. This is calculated at the observer's location. 0 is North, 90 is East, 180 is South and 270 is West. :param float [4]: **Observer Height**. The height of the observer in meters above sea-level. **Example**. In the following example a satellite is positioned so it is at 600 km altitude and is looking at a bearing of 45 degrees (NE) towards a tangent point at 10 km altitude above (52N, -107E). A line of sight is chosen so the instrument is looking in the same geographic bearing at a tangent altitude at 5 km:: from skretrieval.platforms import Platform platform = Platform() utc = ['2020-09-24T18:00:00.0000000'] observer = [52.0, -107.0, 10000.0, 45.0, 600000.0] tanpoint = [5000.0, 45.0] platform.add_measurement_set(utc, ('observer_looking_at_llh', observer), ('tangent_altitude', 'limb', tanpoint)) obspolicy = platform.make_observation_policy() ------------------------------------------------------------------------------------------------------------------------ .. _from_platform: from_platform ------------- The platform is placed at the position returned by a call to :meth:`~.PlatformLocation.update_position` for the universal time of each measurement. The user must configure class :class:`~.Platform` to use the appropriate derived instance of class :class:`~.PlatformLocation` class that meets their needs. .. function:: ( 'from_platform', ) or ('from_platform') No parameters are required. Parameters can be passed in but are ignored. Example:: from skretrieval.platforms import Platform def make_geometry(): platform = Platform() utc = ['2020-09-24T12:15:36.123456', '2020-09-24T12:15:37.456123', '2020-09-24T12:15:38.654321', '2020-09-24T12:15:39.654321'] look = [(35000, 10, 0), (27000, 5, 0), (24000, 0, 0), (21000, -5, 0)] platform.add_measurement_set( utc, ('from_platform',), ('tangent_altitude', 'limb', look) ) obs_policy = platform.make_observation_policy() .. seealso:: Class ER2, class Carmen, class GroundSite, class SatelliteLocator. ------------------------------------------------------------------------------------------------------------------------ .. _rollcontrol: Roll Control ============ Full specification of the platform orientation in space requires the roll of the instrument :math:`\hat{z}_{ICF}` axis around the instrument :math:`\hat{x}_{ICF}` axis. The ``skretrieval.orientation_techniques`` package uses of three methods to determine the location of zero roll, see table below. Each definition has been chosen so the default value of 0.0 corresponds to the value normally chosen for that class of simulations. =========================== ======================================================================================================== Roll Control Setting Description =========================== ======================================================================================================== :ref:`rollcontrol_limb` Limb observations: the zero point of roll is parallel to local up at the tangent point. :ref:`rollcontrol_nadir` Nadir observations: the zero point of roll is parallel to local north at the given point. :ref:`rollcontrol_standard` Aircraft, balloon, ground site: the zero point of roll is parallel to local up at the observer location. =========================== ======================================================================================================== Roll is always measured clockwise when looking along the look vector from the observer's position, i.e. the +Z instrument axis rotates towards the -Y direction, similar to the roll definition used in aircraft systems. The roll control value, if required, is provided as one of the parameters given in each pointing technique declaration and many pointing techniques allow you to omit the value and assume the default value of 0.0. ------------------------------------------------------------------------------------------------------------------------ .. _rollcontrol_limb: limb ---- The ``limb`` roll control setting is typically used for limb viewing geometries. This setting defines the point of zero roll as the point where the instrument :math:`\hat{y}_{ICF}` axis is aligned with the horizon at the tangent point. This is determined by aligning the instrument :math:`\hat{z}_{ICF}` with the vertical unit vector at the tangent point. This ensures the instrument :math:`\hat{y}_{ICF}` axis is parallel to the horizon and points to the portside of the boresight. .. figure:: images/limb_target_geometry.png Limb control aligns instrument :math:`\hat{z}_{ICF}` with the *up* unit vector at the tangent point The ``limb`` roll control setting is not meaningful for several scenarios. For example, look directions that are straight down have poorly defined horizons and result in definitions which at best are not sensible. Similarly look vectors that point upwards only have tangent points that are behind the observer and this, again, results in definitions which are not sensible. The :class:`~.platforms.OrientationTechniques` class will reject all measurement states with the ``limb`` roll control setting if the target tangent point is above the observer's position or is below 5000 meters below the surface of the Earth. ------------------------------------------------------------------------------------------------------------------------ .. _rollcontrol_nadir: nadir ----- The ``nadir`` roll control setting is typically used for nadir viewing geometries. This setting defines the point of zero roll as the point where the instrument :math:`\hat{z}_{ICF}` axis is aligned with geographic *North* at the target point. It is determined by rotating the instrument :math:`\hat{z}_{ICF}` axis around the boresight, :math:`\hat{x}_{ICF}`, until the boresight, the *North* unit vector and the instrument :math:`\hat{z}_{ICF}` are all co-planar with :math:`\hat{z}_{ICF}` co-aligned with *North*. This ensures the instrument :math:`\hat{y}_{ICF}` axis is parallel to the horizon and points to the portside of the boresight. .. figure:: images/nadir_target_geometry.png nadir control aligns instrument :math:`\hat{z}_{ICF}` with the *North* unit vector at the nadir target point The ``nadir`` roll control setting is not meaningful for several scenarios. For example, look directions that are horizontal are poorly defined nadir geometries and result in definitions which, at best, are not sensible. Similarly look vectors that point upwards only have nadir points that are behind the observer and this, again, results in definitions which are not sensible. ------------------------------------------------------------------------------------------------------------------------ .. _rollcontrol_standard: standard -------- The ``standard`` roll control setting is typically used for ground-based sites, aircraft and balloons. The ``standard`` setting defines the point of zero roll as the point where the instrument :math:`\hat{y}_{ICF}` axis is in the horizontal plane at the observer's location. It is determined by rotating the instrument :math:`\hat{z}_{ICF}` axis around the boresight, :math:`\hat{x}_{ICF}`, until the boresight, the *up* unit vector and the instrument :math:`\hat{z}_{ICF}` are all co-planar with :math:`\hat{z}_{ICF}` co-aligned with *up*. .. figure:: images/standard_target_geometry.png ``standard`` roll control places the instrument :math:`\hat{y}_{ICF}` axis in the horizontal plane of the observer. The ``standard`` roll control setting is sensible but has the unfortunate property that it is ill-conditioned for look vectors which are straight up or down as all roll values place :math:`\hat{y}_{ICF}` in the horizontal plane. To assist with this issue, the code allows orientation techniques to specify a horizontal unit vector which is derived from *azimuth* or *yaw* parameters passed in from the user. If the specific orientation technique does not provide hints about the horizontal vector then :class:`~.OrientationTechniques` will choose the *North* direction as the reference horizontal direction for all look vectors. This latter option is not optimal as it results in abrupt changes in roll configuration at angles within ~0.5 degrees of vertical. ------------------------------------------------------------------------------------------------------------------------ .. _pointing_technique: Pointing Technique ================== Pointing techniques are used to rotate the :ref:`pcf` so the instrument boresight, given by the :math:`\hat{x}_{ICF}` unit vector in the :ref:`icf`, is pointing toward the desired target. We have provided a common set of techniques to orient the platform. The orientation techniques only modify the platform rotation matrix. This allows users to define as many look vectors as they wish in the :ref:`icf` and rotate them all, in a consistent fashion, to the final reference frame with the boresight looking at the target location. Pointing techniques are only intended to provide a convenient method of specifying look vectors and users are free to develop their own solutions if they wish. We provide techniques to support common geometries encountered in atmospheric remote sensing, :ref:`rollcontrol_limb`, :ref:`rollcontrol_nadir` and :ref:`rollcontrol_standard`. The various techniques are summarized in the table below. Note that we recommended the :ref:`rollcontrol` setting to be used with each technique but this is only a guideline and users may choose to use other :ref:`rollcontrol` values if it meets their needs. This list of techniques is not extensive by any means and we have built the :class:`OrientationTechniques` class so the new techniques can be added as needs arise, including techniques developed by users. =============================== =============================== ============================================================================================ Pointing Technique Recommended Roll Control Description =============================== =============================== ============================================================================================ :ref:`tangent_xyz_look` :ref:`rollcontrol_limb` Look towards a tangent point with an (x,y,z) unit vector. :ref:`tangent_altitude` :ref:`rollcontrol_limb` Look towards a tangent point with given height and geographic bearing :ref:`att_location_xyz` :ref:`rollcontrol_nadir` Look in nadir towards location given by x,y,z :ref:`att_location_llh` :ref:`rollcontrol_nadir` Look in nadir towards location at geodetic lat, long, height. :ref:`att_from_platform` --- Set platform orientation from :class`~.Platform` class. This is used for real instruments :ref:`att_unit_vectors` --- Set platform orientation with explicit :math:`\hat{x}_{ICF}` and :math:`\hat{z}_{ICF}` unit vectors. :ref:`att_elev_azi_roll` :ref:`rollcontrol_standard` Look in azimuth, elevation and roll direction. :ref:`yaw_pitch_roll` :ref:`rollcontrol_standard` Look in yaw, pitch, roll direction :ref:`tangent_orbplane` :ref:`rollcontrol_limb` Look towards a tangent point with a given height and bearing from the orbit plane. =============================== =============================== ============================================================================================ **Extreme Cases** It is difficult to provide sensible analysis for extreme cases. For example, the roll control zero point is undefined in :ref:`rollcontrol_limb` mode when looking directly downwards. Similar conditions occur when looking horizontally in :ref:`rollcontrol_nadir` mode. The software does detect these extreme conditions and attempts to do something reasonable but we strongly recommend the user only use :ref:`rollcontrol_limb` and :ref:`rollcontrol_nadir` roll control values for sensible and nadir geometries. The :ref:`rollcontrol_standard` setting has difficulties when looking straight up or down if used with techniques intended for :ref:`rollcontrol_nadir` or :ref:`rollcontrol_limb` geometries as the required azimuth of the instrument :math:`\hat{y}_{ICF}` becomes undefined. The problem does not exist for the techniques specifically recommended for :ref:`rollcontrol_standard` roll control as we ensure the users explicitly provides the azimuth information. ------------------------------------------------------------------------------------------------------------------------ .. _tangent_xyz_look: tangent_xyz_look --------------------- Configures the platform so the instrument boresight, :math:`\hat{x}_{ICF}`, points in the specified look direction. The tangent point of the look vector is used as the target location for determining :ref:`rollcontrol` in either :ref:`rollcontrol_limb` or :ref:`rollcontrol_nadir` modes. .. function:: ( 'tangent_xyz_look', roll_control, parameters ) ``parameters`` is an N element array of 3 or 4 element arrays, ``[array[3], array[3], ...]`` or ``[array[4], array[4], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,3) or (N,4). All look vectors are expressed in the :ref:`ecef` :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. Most users will use `limb`. :param float [0]: **x**. The x component of the look direction unit vector :param float [1]: **y**. The y component of the look direction unit vector :param float [2]: **z**. The z component of the look direction unit vector :param float [3]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control* Example:: def configure_look( platform: Platform ): utc = ['2020-09-24T12:15:36.123456', '2020-09-24T12:15:37.456123', '2020-09-24 12:15:38.654321'] pos = [(52, -107, 600000), (52, -107, 600000), (54, -107, 600002)] look = [(0.58311235, -0.43069497, -0.68882642, 0.0), ( 0.58320668, -0.43220012, -0.68780304, 0.0), (0.5833907, -0.43522548, -0.68573615, 0.0)] platform.add_measurement_set('limb', utc, ('llh', pos), ('tangent_xyz_look', 'limb', look)) obspolicy = platform.make_observation_policy() .. note:: This technique is intended to be used for tangent altitudes that are below the observer's position and above 5 km below sea-level. Look vectors outside this range are discarded. ------------------------------------------------------------------------------------------------------------------------ .. _tangent_altitude: tangent_altitude ----------------- The platform looks at the tangent height, geographic bearing and roll specifie in the parameters. This technique should be used to get the instrument boresight look .. function:: ( 'tangent_altitude', roll_control, parameters ) ``parameters`` is an N element array of 2 or 3 element arrays, ``[array[2], array[2], ...]`` or ``[array[3], array[3], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,3) or (N,4). :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. Most users will use `limb`. :param float [0]: **height**. The height in meters above sea-level of the requested tangent altitude. This value should be less than the observers height and greater than 5 km below ground. :param float [1]: **bearing**. The geographic, compass bearing in degrees of the tangent direction measured at the observer's location. 0 is North, 90 is East, 180 is South and 270 is West. :param float [2]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control* ------------------------------------------------------------------------------------------------------------------------ .. _tangent_orbplane: tangent_from_orbitplane ----------------------- The platform looks at the tangent height, bearing and roll specified in the parameters. The bearing is measured from the orbit plane rather than geographic North. This technique is only available on platforms that have a valid *platform_locator* object which calculates *velocity* in addition to *position*. .. function:: ( 'tangent_from_orbitplane', roll_control, parameters ) ``parameters`` is an N element array of 2 or 3 element arrays, ``[array[2], array[2], ...]`` or ``[array[3], array[3], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,3) or (N,4). :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. Most users will use `limb`. :param float [0]: **height**. The height in meters above sea-level of the requested tangent altitude. This value should be less than the observers height and greater than 5 km below ground. :param float [1]: **bearing**. The bearing in degrees of the tangent point from the orbit plane. The forward looking direction, *parallel* to the platform velocity is the point of zero bearing. Bearing increases in the same direction as a compass bearing, i.e. clockwise when viewed from above: North->East->South->West. :param float [2]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control* .. note:: The *platform_locator* can be set when you create an instance of class :class:`~.Platform`. ------------------------------------------------------------------------------------------------------------------------ .. _att_location_xyz: location_xyz ------------------ The platform looks at the given geocentric location (x,y,z) with roll of 'roll' degrees. Typically used for satellite nadir observations .. function:: ( 'location_xyz', roll_control, parameters ) ``parameters`` is an N element array of 3 or 4 element arrays, ``[array[3], array[3], ...]`` or ``[array[4], array[4], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,3) or (N,4). All position vectors are expressed in meters in the :ref:`ecef` :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. :param float [0]: **x**. The x component of the target position vector :param float [1]: **y**. The y component of the target position vector :param float [2]: **z**. The z component of the target position vector :param float [3]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control* ------------------------------------------------------------------------------------------------------------------------ .. _att_location_llh: location_llh ------------------ The platform looks at the given geodetic location (lat, lng, height) with roll of 'roll' degrees. Typically used for satellite nadir observations .. function:: ( 'location_llh', roll_control, parameters ) ``parameters`` is an N element array of 3 or 4 element arrays, ``[array[3], array[3], ...]`` or ``[array[4], array[4], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,3) or (N,4). All position vectors are expressed in meters in the :ref:`ecef` :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. :param float [0]: **Latitude**. The geodetic latitude of the target position in degrees. :param float [1]: **Longitude**. The geodetic longitude of the target position in degrees :param float [2]: **Height**. The height of the target position above sea-level in meters. :param float [3]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control* ------------------------------------------------------------------------------------------------------------------------ .. _att_elev_azi_roll: azi_elev ------------- The platform looks in the direction given by azimuth, elevation and roll (applied in that order). Used for ground sites .. function:: ( 'azi_elev', roll_control, parameters ) ``parameters`` is an N element array of 2 or 3 element arrays, ``[array[2], array[2], ...]`` or ``[array[3], array[3], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,2) or (N,3). :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. :param float [0]: **Azimuth**. The geographic azimuth of the instrument boresight in degrees from North. Measured clockwise from North. 0 is North, 90 is East, 180 is South, 270 is West. :param float [1]: **Elevation**. The elevation in degrees of the instrument boresight from the horizontal plane at the observer's location. Positive elevation (0-90) is upwards. Negative elevation (-90 to 0) is downwards. :param float [2]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control*. Most users will use *standard*. ----------------------------------------------------------------------------------------------------------------------- .. _yaw_pitch_roll: yaw_pitch_roll -------------- The platform applies pointing information in the order yaw, pitch, roll. This is useful for aircraft and balloon systems. Most users will choose to use *standard* :ref:`rollcontrol`. .. function:: ( 'yaw_pitch_roll', roll_control, parameters ) ``parameters`` is an N element array of 2 or 3 element arrays, ``[array[2], array[2], ...]`` or ``[array[3], array[3], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,2) or (N,3). :param str roll_control: The :ref:`rollcontrol` value applied to this set of measurements. :param float [0]: **Yaw**. The geographic bearing of the instrument boresight in degrees from North. Measured clockwise from North. 0 is North, 90 is East, 180 is South, 270 is West. :param float [1]: **Pitch**. The pitch or elevation elevation in degrees of the instrument boresight from the horizontal plane at the observer's location. Positive elevation (0-90) is upwards. Negative elevation (-90 to 0) is downwards. :param float [2]: **roll**. Optional [default 0.0]. The roll angle in degrees of the instrument control frame around the boresight, :math:`\hat{x}_{ICF}`, from the zero point implied by *roll_control*. Most users will use *standard*. ------------------------------------------------------------------------------------------------------------------------ .. _att_from_platform: from_platform -------------- The platform orientation is set by the parameters returned by the :class`~.Platform` class at the required times. This is used for real instruments .. function:: ( 'from_platform',) or ('from_platform') No limb control values or parameters are required. ------------------------------------------------------------------------------------------------------------------------ .. _att_unit_vectors: unit_vectors ------------ The platform orientation is explicitly so the instrument :math:`\hat{x}_{ICF}` and :math:`\hat{z}_{ICF}` are positioned along the two unit-vectors defined by the 6 parameters. The orientation of :math:`\hat{y}_{ICF}` is given by forming a right-handed orthogonal system. The *roll_control* value is ignored. Users should be careful as no checks are made to ensure the input vectors are orthogonal unit vectors. .. function:: ( 'unit_vectors', roll_control, parameters ) ``parameters`` is an N element array of 6 element arrays, ``[array[6], array[6], ...]``. It is anything that can be sensibly coerced into a numpy array of dimension (N,6). :param str roll_control: This parameter is ignored. :param float [0]: **Xx**. The x component of :math:`\hat{x}_{ICF}` in the :ref:`ecef` :param float [1]: **Xy**. The y component of :math:`\hat{x}_{ICF}` in the :ref:`ecef` :param float [2]: **Xz**. The z component of :math:`\hat{x}_{ICF}` in the :ref:`ecef` :param float [0]: **Zx**. The x component of :math:`\hat{z}_{ICF}` in the :ref:`ecef` :param float [1]: **Zy**. The y component of :math:`\hat{z}_{ICF}` in the :ref:`ecef` :param float [2]: **Zz**. The z component of :math:`\hat{z}_{ICF}` in the :ref:`ecef` ------------------------------------------------------------------------------------------------------------------------ Platform Class ============== .. autoclass:: skretrieval.platforms.Platform :members: ------------------------------------------------------------------------------------------------------------------------ Satellite Classes ================= Satellite classes are used to locate the position of a platform. They are derived from class :class:`~platform.PlatformLocation`. General usage of the satellite classes is as follows, #. Create a specific instance of a satellite. #. Update the satellite state vector to a given instant in time, see :meth:`~satellite.PlatformLocation.update_position` #. Get the satellite position, see :meth:`~PlatformLocation.position`, :meth:`~PlatformLocation.earth_location` or :meth:`~PlatformLocation.lat_lon_height` #. Repeat steps 2 and 3. for example:: dt = timedelta(minutes=1.0) # step time of our simulation is one minute numtimes= 1440 # Simulate for 1 day = 1440 * one minute platform_utc = datetime(2019,7,26, hour =20, minute=15, second=00) # start time of our simulation sat = SatelliteSunSync( platform_utc, # Create the satellite orbittype='sgp4', period_from_altitude=600000.0, localtime_of_ascending_node_hours=18.25) answers = np.zeros( [3, numtimes]) # make an array to hold the latitude, longitude, altitude of each satellite at each simulation step times = np.zeros( [numtimes], dtype = 'datetime64[us]') # make an array to hold the UTC time of each simulation step. for i in range(numtimes): # for each time step tnow =platform_utc + i*dt # get the next time step times[i] = tnow # save the time of the step sat.update_position(tnow) # Update the satellite position answers[:,i] = sat.lat_long_height # convert XYZ position and save .. toctree:: :maxdepth: 2 platforms_api/api_satellites ------------------------------------------------------------------------------------------------------------------------ More Details ============= .. toctree:: :maxdepth: 2 intro/transforms platforms_api/api_platform