**************** Reference Frames **************** This required reading document is reproduced from the original NAIF document available at `https://naif.jpl.nasa.gov/pub/naif/misc/toolkit_docs_N0067/C/req/frames.html `_ .. note:: These required readings documents were translated from documentation for N67 CSPICE. These pages may not be updated as frequently as the CSPICE version, and so may be out of date. Please consult the changelog_ for more information. .. _changelog: ./changelog.html .. important:: NOTE any functions postfixed by "_" mentioned below are Fortan-SPICE functions unavailable in SpiceyPy as the NAIF does not officially support these with "_c" function wrappers within the CSPICE API. If these functions are necessary for your work please contact the NAIF to request that they be added to the CSPICE API Abstract ========= | The frames subsystem specifies the relationships of various kinds of reference frames supported by SPICE. This facilitates `behind-the-scenes` transformations between these frames. Purpose ------- | This document describes how reference frames are treated within SPICE. The document includes a general discussion of reference frames, detailed information about various types of frames supported within SPICE, and instructions on defining additional reference frames to assist in a user's computations. Intended Audience ----------------- | This document addresses the needs of several groups of users. Users looking for a basic discussion of reference frames and a list of the frames supported by the SPICE system should read the chapter `Using Frames.` Users desiring to customize their environment by adding new frames should read the chapter `Creating a Frame Kernel.` This document assumes you have some familiarity with SPICE concepts and terminology. If you are new to the SPICE system, or just a bit rusty with it, you should consider reviewing `An Overview of the SPICE System` and `An Introduction to SPICE.` Using Frames ============ | Frame Functions in SPICE ------------------------- | The SPICE frame subsystem facilitates `behind-the-scenes` frame transformations. This allows you to concentrate on questions more closely related to the problem you are trying to solve instead of the details of on how to get position or state vectors in the frame of interest. Frame Transformation Functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | Several user-level CSPICE functions require that the user supply the name of a reference frame as one of the inputs to the function. The most important of these is the function :py:meth:`~spiceypy.spiceypy.spkezr`. This function returns the state (Cartesian position and velocity) of one object relative to another in a user specified reference frame. The choice of reference frame often makes a big difference in the usefulness of a returned state. If the state is given relative to the reference frame of interest to the user, computations involving that state can be much simpler than if the state is returned relative to some other reference frame. The two user-level interface functions that deal solely with frame transformations are :py:meth:`~spiceypy.spiceypy.sxform` and :py:meth:`~spiceypy.spiceypy.pxform`. sxform_c supports transformations of Cartesian state vectors (6 components) between reference frames while :py:meth:`~spiceypy.spiceypy.pxform` supports transformations of Cartesian position vectors (3 components). :py:meth:`~spiceypy.spiceypy.pxform` may be used when only position information is needed, or when the derivatives required for a state transformation are unavailable, for example when one frame is defined by a C-kernel that lacks angular velocity data. The calling sequences for these functions are .. code-block:: python xform = sxform( from, to, et ) rotate = pxform( from, to, et ) The output of :py:meth:`~spiceypy.spiceypy.sxform`, \`xform', is a 6 by 6 matrix used to transform state vectors relative to a reference frame, the name of which is specified by the \`from' input argument, to states relative to another reference frame, the name of which is specified by the \`to' input argument, at the epoch \`et' (specified in seconds past J2000). The output of :py:meth:`~spiceypy.spiceypy.pxform`, \`rotate', is a 3 by 3 transformation matrix equivalent to the upper left 3x3 block of \`xform'. This matrix transforms position as opposed to state vectors. Frame Information Functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | The SPICE frame subsystem contains a set of functions that enable applications to retrieve information about frames known to SPICE, whether they are built-in or specified by means of frame kernels: :py:meth:`~spiceypy.spiceypy.frmnam` Convert frame ID code to frame name. :py:meth:`~spiceypy.spiceypy.namfrm` Convert frame name to frame ID code. :py:meth:`~spiceypy.spiceypy.frinfo` Return frame specification parameters: frame center, frame class, and frame class ID. :py:meth:`~spiceypy.spiceypy.cidfrm` Map body ID code to the default frame centered on the specified body. Both frame name and ID are returned. :py:meth:`~spiceypy.spiceypy.cnmfrm` Map body name to the default frame centered on the specified body. Both frame name and ID are returned. :py:meth:`~spiceypy.spiceypy.ccifrm` Map frame class and class ID to frame specification parameters: frame ID code, frame name and frame center are returned. This function provides a way to identify frames referenced in CK and PCK files: in these files, segment descriptors contain class IDs of frames. See the section `Specifying a New Frame` below for more information on frame specification parameters. Frames Supported in SPICE -------------------------- | In both cases -- with the functions requiring specification of a reference frame as one of the inputs (for example :py:meth:`~spiceypy.spiceypy.spkezr`), and with the functions computing transformation between two reference frames (:py:meth:`~spiceypy.spiceypy.sxform` and :py:meth:`~spiceypy.spiceypy.pxform`) -- you specify the frame or frames of interest using a character string that contains the name of the reference frame. In SPICE function interfaces, frames are typically designated by C strings. In text kernel files, frame names are designated by strings delimited by single quotes, as in FORTRAN. Examples below showing single-quoted frame names exhibit the names as they appear in text kernels; these same names are double-quoted when referred to as literal strings in C source code. A number of names are automatically recognized by the frame subsystem because the definitions for these frames are `built into` SPICE software. Among these frames are: - inertial frames such as Earth mean equator and equinox of J2000 frame ('J2000'), Mean ecliptic and equinox of J2000 ('ECLIPJ2000'), Galactic System II frame ('GALACTIC'), Mars Mean Equator and IAU vector of J2000 frame ('MARSIAU'), etc. For the complete list of `built in` inertial reference frames refer to the appendix `built in Inertial Reference Frames` of this document. - The ICRF is a special case. See the section titled `ICRF vs J2000` below. - body-fixed frames based on IAU rotation models provided in text PCK files, such as Earth body-fixed rotating frame ('IAU_EARTH') and Mars body-fixed rotating frame ('IAU_MARS'), and body-fixed frames based on high precision Earth rotation models provided in binary PCK files such as 'ITRF93'. For the complete lists of `built in` body-fixed reference frames refer to the appendixes `built in PCK-Based Reference Frames` and High Precision Earth Fixed Frames` of this document. For all other frames the names are not `built into` SPICE. Instead, these names, as well as the parameters specifying the frames, are provided via keywords included in a text kernel file. Text kernel frame definitions cannot overwrite definitions `built into` SPICE. The `built-in` frames are always accessed first, making text kernel frames with the same names or IDs invisible to the Toolkit. The types of frames defined in text kernels include: - body-fixed frames based on text or binary PCK data for bodies whose rotational data is not yet included in the IAU rotational constants reports - CK-based frames, i.e. frames for which orientation is provided in CK files - Fixed offset frames, i.e. frames for which orientation is constant with respect to another frame and is specified as part of the frame definition stored in a text kernel. Fixed offset frames are also called TK frames. - Dynamic frames, i.e. frames for which orientation is based on dynamic directions computed based on SPICE kernel data (SPKs, CK, PCKs), on mathematical models implemented in CSPICE functions, or on formulas defined in frame kernels. - Switch frames, i.e. frames that choose at run time other frames with which to align their orientation. Switch frames `switch` the base frames they align with as a function of time, using a prioritized list of base frames and optional, associated time bounds; this list is provided as part of the switch frame definition stored in a text kernel. You can find the names of these frames by examining the text kernel file that contains the frame definitions. Normally definitions of all frames specific for a given mission are stored in that mission's Frames Kernel (FK) file but they can also be provided in the Instrument Kernels (IK) or any other text kernels. In order to make frame definitions from the text kernels available to SPICE, these kernels need to be loaded via a call to :py:meth:`~spiceypy.spiceypy.furnsh`. For example, to load an FK named `myframe.tf`, call :py:meth:`~spiceypy.spiceypy.furnsh` as follows: .. code-block:: python furnsh( "myframe.tf" ) ICRF vs J2000 --------------- | The International Celestial Reference System (ICRS) defines coordinate axes that are closely aligned with those of the J2000 (aka EME2000) reference frame. The International Celestial Reference Frame (ICRF) and later versions of it (ICRF1, etc.) are realizations of the ICRS. For brevity, we'll simply refer to `the ICRF` below. The rotational offset between the J2000 frame and the ICRS has magnitude of under 0.1 arcseconds. Certain JPL data products are referenced to the ICRF or later versions of it. These include, but are not limited to, - DE4xx series planetary ephemerides - Satellite ephemerides compatible with DE4xx planetary ephemerides - Small body ephemerides compatible with DE4xx planetary ephemerides - Orientation of the terrestrial frame ITRF93 - Orientation of the lunar principal axes frame Rotation models provided by the IAU are referenced to the ICRF. Modern spacecraft ephemerides and attitude data, other than those for Earth orbiters, are likely referenced to the ICRF. Users should consult documentation or data providers to verify this for data sets of interest. SPK and binary PCK files produced by NAIF from the data sources listed above are referenced to the same version of the ICRF as the corresponding data sources. For historical and backward compatibility reasons, these data products are labeled as being referenced to the J2000 frame. No transformation is required to convert state vectors or orientation data from the J2000 frame to the ICRF (or later version), if the vectors or orientation data are computed using SPICE kernels created from the data sources listed above. For example: - A call to :py:meth:`~spiceypy.spiceypy.spkezr` with the input frame name J2000 will return a state vector referenced to the ICRF, if the SPK data are from a JPL planetary ephemeris SPK, or from any other SPK in which data are referenced to the ICRF and labeled as referenced to the J2000 frame. - A call to :py:meth:`~spiceypy.spiceypy.pxform` with the input `from` frame name J2000 and input `to` frame name ITRF93 will return a 3x3 matrix that transforms position vectors from the ICRF to the ITRF93 terrestrial frame, if the Earth orientation data are provided by a NAIF high-precision, binary Earth PCK. - A call to :py:meth:`~spiceypy.spiceypy.pxform` with the input `from` frame name J2000 and input `to` frame name IAU_MARS will return a 3x3 matrix that transforms position vectors from the ICRF to the Mars body-fixed, body-centered IAU_MARS frame, if the orientation data are provided by a NAIF generic text PCK. - A call to :py:meth:`~spiceypy.spiceypy.pxform` with the input `from` frame name J2000 and an input `to` CK frame name will return a 3x3 matrix that transforms position vectors from the ICRF to the specified CK frame, if the CK data used by this call are referenced to the ICRF and labeled as referenced to the J2000 frame. SPICE kernel creators intending to support use of data referenced to the ICRF, as shown above, should write the data without first converting it to the J2000 frame. Segments of such SPK, CK, or binary PCK files should indicate the frame is J2000. It is strongly recommended that kernel creators add comments to the files to explain the actual characteristics of the data. SPICE users who export kernel data to non-SPICE file formats may need to transform the data, depending on the frame to which the SPICE data are actually referenced (as opposed to the frame to which the kernel indicates the data are referenced), and depending on the desired output frame. Kernels Needed For Computing Frame Transformations --------------------------------------------------- | In many cases data needed to compute transformation of one frame relative to another is stored in SPICE kernels: PCK, CK, FK, and even SPK. The appropriate kernels must be loaded for the SPICE system to compute a frame transformation from a non-inertial frame to any other frame. The `built in` inertial frames are the only frames the transformations between which can be computed without loading any SPICE kernels. Since the body-fixed frames are tied to the rotation of planets, satellites, asteroids, etc, the information about how the orientation of these frames is changing with respect to inertial frames is stored in SPICE PCK files. It is important to note that although the names of these frames are `built in` their relationship to inertial frames is not. This information must be `loaded` into the SPICE system from a PCK file. Without loading this information you cannot compute the transformation to or from a body-fixed frame. As the name suggests, the orientation of CK-based frames is computed using data provided in CK files and cannot be computed without loading these. In addition to the CKs, an SCLK kernel establishing time correlation for the on-board clock that is used to tag data in the CKs must be loaded to support time conversion between that clock and ephemeris time. Because the fixed offset frame definitions stored in text kernels provide all information needed to determine their orientation relative to the frame with respect to which they are defined, only the text kernel containing the definition need be loaded. Depending on the particular family to which a dynamic frame belongs, no additional data may be needed in order to compute its orientation, or one or more types of SPICE kernels, including SPKs, PCKs, CKs, and SCLK, may have to be loaded. Data required to compute orientation of switch frames may be any required to compute orientation of PCK, CK, or TK frames. Data for dynamic and switch base frames are not required because the orientation of a switch frame relative to base frames of those types is the identity. In practice, data sufficient to connect the orientation of a switch frame's base frames to other frames of interest are required by most applications. Creating a Frame Kernel ======================== | To create a frame kernel you will need to understand the SPICE text kernel file format described in detail in the Kernel Required Reading document, `kernel.req <./kernel.html>`__. When making a new frame kernel, make sure that the first line of the file contains the proper SPICE file identification word for the FK files -- `KPL/FK` -- left-justified, on a line by itself. You will also need to understand the concept of a frame class. Frame Classes -------------- | The method by which a frame is related to some other frame is a function of the `class` of the frame. You describe the class of a frame with an integer called the frame's `class number.` The reference frame classes are enumerated below. #. Inertial frames. These frames do not rotate with respect to the star background. They are the frames in which Newton's laws of motion apply. The class number associated with inertial frames is 1. #. PCK (body-fixed) frames. PCK frames are reference frames whose orientation with respect to inertial frames is supplied through either binary or text PCK files. To determine a transformation to or from a PCK frame, you must load a PCK file that describes the orientation of the frame with respect to one of the inertial frames `built into` SPICE. The class number associated with PCK frames is 2. #. CK frames. CK frames are reference frames whose orientation with respect to some other reference frame is supplied via a SPICE C-kernel. The other reference frame may be any of the four classes of frames described here. C-kernels use spacecraft clock `ticks` as their basic time unit. Consequently you need to load a spacecraft clock kernel appropriate for the C-kernel to determine the transformation from or to a C-kernel frame. In addition you will need to load a PCK, CK, or TK frame kernel if the `other` frame belongs to one of these classes. The class number associated with CK frames is 3. #. Fixed offset frames. These frames are also called Text Kernel (TK) frames because they have a constant orientation with respect to some other reference frame and this orientation is included in the frame definition provided in a SPICE text kernel. They may be defined relative to a frame of any of the other classes of reference frames. The class number associated with TK frames is 4. #. Dynamic frames. These are time-dependent reference frames defined via parameters or formulas specified in a frame kernel. The class number associated with dynamic frames is 5. #. Switch frames. These are time-dependent frames that choose at run time other frames with which to align their orientation. Switch frames `switch` the base frames they align with as a function of time, using a prioritized list of base frames and optional, associated time bounds; this list is provided as part of the switch frame definition stored in a text kernel. The class number associated with switch frames is 6. Specifying a New Frame ---------------------- | In addition to the data/model needed to specify the orientation of a frame with respect to some other reference frame, you must tell the SPICE system how to find the data or model. This specification requires five pieces of information: #. the name of the frame, #. the ID code for the frame, #. the class number of the frame, #. the SPK ID code or name for the frame center, #. the internal ID code used by the class (CLASS_ID) to refer to the frame. The rules for selecting these items are given in the next section, but for the moment let's assume that the rules have been obeyed and we have arrived at the following values. .. code-block:: text Frame Name : 'WALDO' Frame ID code : 1234567 (A number guaranteed to be suitable for private use) Frame Class : 3 (C-kernel) Frame Center : -10001 (Waldo Spacecraft ID code) Frame Class_id: -10000001 (ID code in C-kernel for Waldo) The frame kernel that specifies this frame is given below: .. code-block:: text \begindata FRAME_WALDO = 1234567 FRAME_1234567_NAME = 'WALDO' FRAME_1234567_CLASS = 3 FRAME_1234567_CENTER = -10001 FRAME_1234567_CLASS_ID = -10000001 \begintext Note that single quotes are used to delimit strings in SPICE text kernels. Guidelines for Frame Specification ----------------------------------- | Selecting a Name ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | The name chosen for a frame must not exceed 26 characters taken from the set including uppercase letters, numbers, underscore, and plus and minus signs. It should have some mnemonic value so that users can recognize what the name means. Finally, it should not be the name of one of the `built in` frames listed above or the name of any other frame you wish to specify. If you try to use a `built in` name, the frame subsystem will ignore your frame specification. In the example given above, we chose the name 'WALDO' for the name of our reference frame. If `Waldo` would be a lander and would need to specify a local level frame at its landing site, we could have named that frame 'WALDO_LOCAL_LEVEL'. A good name for a frame associated with the camera flown on `Waldo` would be 'WALDO_CAMERA'. Selecting a Frame ID ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | What you choose for a frame ID depends upon the class of the frame. If the class is CK, you may use the same ID as you use for the CLASS_ID. In the previous example, we selected the Frame ID to be .. note:: Since our example frame above is of class 3, a CK frame, we would normally use the same number for the frame ID as we used for the class ID. However, in this example, we have chosen a different value to illustrate the connection between the frame ID and the variables needed to define the frame. For TK frames, the frame and class IDs must be identical. For TK frames associated with an instrument, the instrument ID is used for both frame ID and class ID. For topocentric TK frames at tracking station sites, both frame ID and class ID are created by `combining` the ID of the body on which the station is located with the station number (for example frame and class ID 1399012 is used for `DSS-12`, with the formula used to arrive at this ID being 1000000 + `Earth ID`*1000 + `station ID`.) For local level and surface fixed TK frames at a landing site, both frame ID and class ID are based on the ID of the lander (for example frame and class ID of -222999 would be the natural choice for the lander with ID -222.) If the frame is a PCK frame or a dynamic frame and you are working without consultation with NAIF, select an integer in the range from 1400000 to 2000000. Selecting the Class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | This is usually the easiest part of specifying a frame. Presumably you know how the orientation of the frame with respect to some other frame will be computed. Simply choose the appropriate class number. In the example above, the class number is 3 because we are defining a CK-based frame. Selecting the Center ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | A frame is used to specify the orientation of some object. The frame consists of a set of coordinate axes relative to some point -- the origin of the reference frame. When viewed from some other frame the axes rotate about the origin. The origin about which the rotation takes place is the center of the frame. For body-fixed frames this is the center of the body to which they are fixed. For C-kernel frames the center is often the spacecraft whose orientation is provided by the C-kernel. Simply find the SPK ID code or name for the object to which the frame is attached and use that as the value for the center. In our example, the SPK ID code for the `Waldo` spacecraft is -10001. Note that this center ID is used to look up the position of the frame origin when SPICE computes frame orientation adjusted for light time. Therefore, only centers for which supporting SPK data are expected to be available should be picked. It is usually an issue only for TK and CK frames associated with instruments because the positions of instruments are rarely available in SPKs. To get around the need to provide the instrument positions, it is appropriate to specify the ID of the spacecraft on which an instrument is mounted as the center of a TK or CK frame associated with it. Selecting a Class ID ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | A frame's `CLASS_ID` is an integer used internally by CSPICE software. It is the integer code used by the CSPICE reference frame subsystem to look up reference frame information. If your frame is a PCK class frame the CLASS_ID is the ID code for the body for which rotation constants are provided in the text PCK file or the ID associated with the orientation data provided in the binary PCK file. If your frame is a CK class frame, the CLASS_ID is the ID code used in the C-kernel to describe the orientation of the spacecraft. If the frame is a TK frame, the class ID must match the frame ID. If the frame is a dynamic frame, the class ID must match the frame ID. If the frame is a switch frame, it is recommended that the class ID match the frame ID. Frame IDs Reserved for Public Use ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | The range 1400000 to 2000000 has been set aside by NAIF as ranges of Frame IDs that can be used freely by SPICE users without fear of conflict with `officially recognized` frames. However, if you and a colleague plan to create several such frames, you will need to coordinate your work to ensure that your definitions are not in conflict with one another. Why have a Frame ID and a Class ID? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | When the CSPICE software receives a request to compute a frame transformation, it first translates the name of the frame to the corresponding frame ID. There is a one to one correspondence between frame names and frame IDs. Once the frame ID is in hand, the class of the frame can be located and an appropriate subsystem identified for carrying out the initial computations needed to construct a frame transformation matrix. However, the frame subsystem evolved to unify several distinct reference frame systems. In each of these systems, reference frames are identified by integer codes. Unfortunately, since these subsystems evolved independently, the numeric codes used to identify the reference systems overlapped from one system to the next. Moreover, to support backward compatibility, NAIF was not free to change the numeric codes used by the various systems or the meaning of the frame codes that were already present in existing data products. To support existing data products and allow extension of the SPICE system, NAIF needed to associate the old ID code with the new frame ID. The CLASS_ID fills this role. When the frame is identified, the ID code suitable for the frame class is located and passed onto the frame's class so that the initial portion of the frame transformation can be carried out. Putting the Pieces Together ----------------------------- | Once you've determined the name, ID code, center, class and class ID of your frame, you create the frame specification by filling in the frame template below. This should be stored in a text kernel called a Frame Specification Kernel or Frames Kernel (FK). .. code-block:: text FRAME_ = FRAME__NAME = '' FRAME__CLASS = FRAME__CLASS_ID = FRAME__CENTER =
The example we used for the frame 'WALDO' illustrates this. .. code-block:: text \begindata FRAME_WALDO = 1234567 FRAME_1234567_NAME = 'WALDO' FRAME_1234567_CLASS = 3 FRAME_1234567_CENTER = -10001 FRAME_1234567_CLASS_ID = -10000001 \begintext Once you've completed the frame specification you tell the SPICE system about the frame by `loading` the frame kernel that contains it. As with all text kernels, you load it via the routine :py:meth:`~spiceypy.spiceypy.furnsh`. For example if the frame kernel containing your frame specification is contained in the file `myframe.tf` you load the kernel via the call .. code-block:: python furnsh( "myframe.tf" ) Connecting an Object to its Body-fixed Frame --------------------------------------------- | Every extended object has both a position and orientation in space. The SPICE ephemeris subsystem (SPK) allows you to specify the location of such an object. The frame subsystem allows you to name the body-fixed frame that describes the orientation of the object, and to retrieve the orientation of the frame relative to some other frame as a function of time. Given the name or SPK ID code associated with an object we can locate its position through the SPK subsystem. Unfortunately, the body-fixed frame of the object cannot always be determined from the object's name or ID code. For example, we have already mentioned that there are two `built in` reference frames that describe the orientation of the Earth: 'IAU_EARTH' and 'ITRF93'. For other objects, such as the asteroid Simbad, there is no `built in` frame associated with the object. The body-fixed frame of Simbad must be defined through a text kernel. In both cases, the connection between the object and its body-fixed frame needs to be supplied via a kernel pool variable. There are two ways to do this. .. code-block:: text OBJECT__FRAME = '' or .. code-block:: text OBJECT__FRAME = You may use the ID codes for either the object, the frame or both. As example, four of the following assignments could serve to connect the Earth with the 'ITRF93' frame. .. code-block:: text OBJECT_399_FRAME = 13000 OBJECT_399_FRAME = 'ITRF93' OBJECT_EARTH_FRAME = 13000 OBJECT_EARTH_FRAME = 'ITRF93' Note: if you use the name of either the object or frame, you must use upper case letters. Of these four means of specifying an object's body-fixed frame the second (OBJECT_399_FRAME = 'ITRF93') is the most robust. For the sun, the planets and their satellites the frame subsystem maintains a default connection between the object and its body-fixed frame `built into` SPICE. The complete list of `built in` body-fixed frames is provided in the `built in PCK-Based IAU Body-Fixed Reference Frames` appendix of this document. The rest of the frame information ---------------------------------- | The information supplied in the frame specification tells the SPICE system where to look for a particular frame model. However, the specification alone doesn't tell the SPICE system how to actually transform from the specified frame to some other frame of interest. To do this you need to supply other information. How this information is supplied depends upon the class of the frame. Inertial Frames =============== | Inertial frames are `built into` the SPICE system via the routine chgirf\_. Only the frames defined in that routine are available as inertial (class 1) frames. It is not possible to override these definitions. It is possible to create aliases for built-in inertial frames. For example you might define EME2000 as another name for the J2000 frame. See the appendix containing frame definition examples for information on how to create a frame alias using a TK frame. PCK Frames =========== | If you specify a PCK frame, you will need to load either a text or binary PCK file for the body with which the frame is associated. The construction of PC kernels is discussed in the SPICE document PCK Required Reading (`pck <./pck.html>`__.) CK Frames ========= | If a frame is defined as a CK frame, you will need both a C-kernel for the structure identified by the FRAME\_..._CLASS_ID variable and an SCLK kernel for converting ephemeris time to the `ticks` used to represent time in the C-kernel. Both the C-kernel(s) and SCLK kernel must be loaded prior to attempting to use the CK frame. SCLK and SPK ID codes ---------------------- | For many C-kernels, the spacecraft clock and spacecraft ID codes can be determined by performing an integer division of the C-kernel ID code by 1000. However, under some circumstances this numerical correspondence between C-kernel ID code and the associated SCLK or spacecraft ID may break down. When the numerical relationship fails you need to tell the SPICE system the ID code of the SCLK or spacecraft via two kernel pool variables. .. code-block:: text CK__SCLK = CK__SPK = These variables are normally placed in either the SCLK kernel or in the frame specification kernel (FK). To illustrate how you would create a C-kernel frame, we shall suppose that we have a C-kernel for structure -100001 aboard the fictional spacecraft `Waldo` which has ID code -1001. Moreover we shall assume that the clock ID appropriate for this structure is -1002. Below is a frame specification together with the CK\_..._SCLK and CK\_..._SPK variable definitions for the 'WALDO' frame. .. code-block:: text \begindata FRAME_WALDO = -100001 FRAME_-100001_NAME = 'WALDO' FRAME_-100001_CLASS = 3 FRAME_-100001_CLASS_ID = -100001 FRAME_-100001_CENTER = -1001 CK_-100001_SCLK = -1002 CK_-100001_SPK = -1001 \begintext TK Frames ========= | The relationship between a constant offset Text Kernel (TK) frame and the frame it is offset from is given via a text kernel that can be loaded via the kernel pool routine :py:meth:`~spiceypy.spiceypy.furnsh`. The first five kernel pool variables required for TK frame specification are the same as for any other frame defined via a text kernel: .. code-block:: text FRAME_ = FRAME__NAME = '' FRAME__CLASS = 4 FRAME__CLASS_ID = FRAME__CENTER =
You need to supply information that indicates the frame, RELATIVE, from which the TK frame is offset. It is done using this kernel pool variable: .. code-block:: text TKFRAME__RELATIVE = '' where `frame` is the ID code or name you used in the frame specification. Because the rotation from the TK frame to the RELATIVE frame is fixed (time invariant) it can be specified in the FK along with the frame specification information described above. This rotation data can be provided in any of three ways: #. as a 3 by 3 matrix, M, that converts vectors from the TK frame to the RELATIVE frame by left multiplication .. code-block:: text V_relative = M * V_tkframe #. as a set of 3 Euler angles and axes that can be used to produce M #. as a SPICE-style quaternion representing M. You let the frame subsystem know which method you've chosen for representing the rotation via the kernel pool variable .. code-block:: text TKFRAME__SPEC. To use a matrix to define the rotation, use the assignment: .. code-block:: text TKFRAME__SPEC = 'MATRIX' To define the rotation via three Euler angles, use the assignment: .. code-block:: text TKFRAME__SPEC = 'ANGLES' To define the rotation via a SPICE-style quaternion, use the assignment: .. code-block:: text TKFRAME__SPEC = 'QUATERNION' Depending upon the value of the `SPEC` variable, you need to supply one of the following sets of kernel pool variables. Defining a TK Frame Using a Matrix ----------------------------------- | If you've chosen to define the rotation using a matrix, supply the matrix using the kernel pool variable assignment below: .. code-block:: text TKFRAME__MATRIX = ( matrix_value[0][0], matrix_value[1][0], matrix_value[2][0], matrix_value[0][1], matrix_value[1][1], matrix_value[2][1], matrix_value[0][2], matrix_value[1][2], matrix_value[2][2] ) For example, if the matrix defining your TK frame is .. code-block:: text 0.4 -0.6 0.0 0.6 0.4 0.0 0.0 0.0 1.0 and the ID code you've selected for the frame is 1234567, then you would supply the following information in a text kernel. .. code-block:: text TKFRAME_1234567_SPEC = 'MATRIX' TKFRAME_1234567_MATRIX = ( 0.4 0.6 0.0 -0.6 0.4 0.0 0.0 0.0 1.0 ) Defining a TK Frame Using Euler Angles ---------------------------------------- | If you've chosen to define a TK frame as a sequence of three Euler angle rotations about specified coordinate axes, you need to supply the following pieces of information: #. The values of the three Euler angles; #. The axes about which the Euler rotations are performed; #. The units associated with the three Euler angles. The recognized units are: 'DEGREES', 'RADIANS', 'ARCSECONDS', 'ARCMINUTES' 'HOURANGLE', 'MINUTEANGLE', 'SECONDANGLE'. This information is supplied to the SPICE system using the kernel pool variables shown below. .. code-block:: text TKFRAME__ANGLES = ( angle_1, angle_2, angle_3 ) TKFRAME__AXES = ( axis_1, axis_2, axis_3 ) TKFRAME__UNITS = 'units_of_angles' The units must be from the list given above. The axes must be chosen from the set of integers 1,2,3 where 1 stands for the x-axis, 2 for the y-axis, and 3 for the z-axis. If M is the matrix that converts vectors relative to the TK frame to the RELATIVE frame by left multiplication, then the angles and axes must satisfy the following relationship: .. code-block:: text M = [angle_1] [angle_2] [angle_3] axis_1 axis_2 axis_3 where the symbol .. code-block:: text [ A ] i stands for a rotation by the angle A about the i'th axis. .. code-block:: text +- -+ | 1 0 0 | | 0 cos A sin A | = [ A ] | 0 -sin A cos A | 1 +- -+ +- -+ | cos A 0 -sin A | | 0 1 0 | = [ A ] | sin A 0 cos A | 2 +- -+ +- -+ | cos A sin A 0 | | -sin A cos A 0 | = [ A ] | 0 0 1 | 3 +- -+ This method of definition is particularly well suited for defining topocentric frames on the surface of the Earth. For example, suppose you have an SPK (ephemeris) file that specifies the location of some surface point on the Earth, and that the SPK ID code of this point is Moreover suppose you have the geodetic co-latitude (COLAT) and longitude (LONG) measured in degrees for this point. (Note that the co-latitude is the complement of latitude: latitude + co-latitude = 90 degrees.) Given this information we can easily define a topocentric reference frame at the point such that the x-axis points north along the local meridian, the y-axis points west along the local latitude and the z-axis points up from the reference spheroid. The transformation from Earth body-fixed frame to topocentric frame is given by .. code-block:: text BF2TP = [180] [COLAT] [LONG] 3 2 3 Consequently the transformation from the topocentric frame to the body-fixed frame is given by .. code-block:: text M = TP2BF = [-LONG] [-COLAT] [180] 3 2 3 Let 1234567 be the ID code for the topocentric frame; let the name of this frame be 'MYTOPO'; and define this relative to the IAU frame for the Earth (one of the `built in` frames). The topocentric frame at the ephemeris point 399100 is specified as shown below: .. code-block:: text \begindata FRAME_MYTOPO = 1234567 FRAME_1234567_NAME = 'MYTOPO' FRAME_1234567_CLASS = 4 FRAME_1234567_CLASS_ID = 1234567 FRAME_1234567_CENTER = 399100 TKFRAME_1234567_SPEC = 'ANGLES' TKFRAME_1234567_RELATIVE = 'IAU_EARTH' TKFRAME_1234567_ANGLES = ( <-long>, <-colat>, 180 ) TKFRAME_1234567_AXES = ( 3, 2, 3 ) TKFRAME_1234567_UNITS = 'DEGREES' \begintext As we'll see a bit later, we can make a more flexible definition for this topocentric frame. Defining a TK Frame Using a SPICE-style Quaternion --------------------------------------------------- | If you've chosen to define a TK frame using a SPICE-style quaternion, supply the quaternion using the kernel pool variable assignment below: .. code-block:: text TKFRAME__Q = ( q_0, q_1, q_2, q_3 ) where component zero is the so-called `real` component of the quaternion (the `cosine` component of the quaternion). The last 3 components (components 1 through 3) are the `axis` components of the quaternion -- the i, j, and k components respectively of the quaternion. The quaternion must be a unit quaternion. .. code-block:: text 2 2 2 2 (q_0) + (q_1) + (q_2) + (q_3) = 1 A more detailed discussion of quaternions is available in the reference document `Rotations Required Reading` (`rotation.req `__), and in a `Quaternions White Paper` available from NAIF. Gaining Flexibility via TK Frames ----------------------------------- | The use of non-inertial frames gives you an easy means of creating ephemerides for points on the surface of a body such as the Earth, Moon or Mars. The ephemeris is simply the body-fixed location of the object relative to a body-fixed frame for the same object. However, the model used to relate the body-fixed frame to other reference frames may not be fixed. Indeed, for the Earth there are several different methods with varying degrees of accuracy that give the orientation of the Earth with respect to inertial space. Each of these different realizations may have a different frame ID code. This ability to `plug in` different orientations is one of the strengths of the SPICE system. However, if you create an ephemeris relative to one of these specific models, you won't be able to use it unless you've loaded the correct model. To make the ephemeris usable regardless of the orientation model you happen to have at your disposal, you should define the body-fixed ephemeris relative to a TK frame. Then define the TK frame so that rotation from the TK frame to the PCK frame is the identity matrix. For example, you can define a lunar body-fixed frame as shown below. .. code-block:: text \begindata FRAME_MOONFIXED = 3010000 FRAME_3010000_NAME = 'MOONFIXED' FRAME_3010000_CLASS = 4 FRAME_3010000_CLASS_ID = 3010000 FRAME_3010000_CENTER = 301 TKFRAME_3010000_SPEC = 'MATRIX' TKFRAME_3010000_RELATIVE = '' TKFRAME_3010000_MATRIX = ( 1, 0, 0, 0, 1, 0, 0, 0, 1 ) \begintext By editing this definition you can make the MOONFIXED frame be the IAU MOON frame or some other model if one is available. Or you can create several such definitions and, at run-time, load the file that best fits your current environment. Using this indirect method of defining the various frames for which more than one orientation model may be available, you can avoid limiting how various kernels can be used. Dynamic Frames ================= | In SPICE documentation, the term `dynamic frame` designates a time-dependent reference frame defined via a frame kernel. A `parameterized dynamic frame` is a dynamic frame defined by a formula implemented in CSPICE code and having user-selectable parameters set via a frame kernel. The formula defining a dynamic frame may rely on data from other SPICE kernels, for example state vectors provided by SPK files or rotation matrices from C-kernels or PCK files. An example of a parameterized dynamic frame is a nadir-pointing reference frame for a spacecraft orbiting a planet, where the spacecraft's nadir direction and velocity vector define the frame. Using a frame kernel, a CSPICE user may specify the planet and spacecraft, the relationship between the nadir and velocity vectors and the frame's axes, and a small set of additional parameters required to define the frame. Currently parameterized dynamic frames are the only type of dynamic frame supported by CSPICE. Other types of dynamic frames, such as frames defined by complete formulas (as opposed to parameters) provided in frame kernels, may be implemented in future versions of CSPICE. Below we'll discuss the various types of supported dynamic frames, how to create frame kernels that define dynamic frames, and dynamic frame implementation considerations. The appendix `Frame Definition Examples` contains frame definition templates for a variety of popular dynamic frames. Parameterized Dynamic Frame Families ===================================== | The `family` to which a parameterized dynamic frame belongs indicates the underlying mathematical formula by which the frame is defined. Currently there are six parameterized dynamic frame families: - Two-vector frames: a reference frame is defined by two vectors. The first vector is parallel to one axis of the frame; the component of the second vector orthogonal to the first is parallel to another axis of the frame, and the cross product of the two vectors is parallel to the remaining axis. - Mean equator and equinox of date frames: these use mathematical precession models to define orientation of a body's equatorial plane and location of the frame's x-axis. Currently these frames are supported only for the earth. - True equator and equinox of date frames: these use mathematical precession and nutation models to define orientation of a body's equatorial plane and location of the frame's x-axis. Currently these frames are supported only for the earth. - Mean ecliptic and equinox of date frames: these use mathematical precession and mean obliquity models to define orientation of a body's orbital plane and location of the frame's x-axis. Currently these frames are supported only for the earth. - Euler frames: polynomial coefficients, a reference epoch, and an axis sequence are used to specify time-dependent Euler angles giving the orientation of the frame relative to a second, specified frame as a function of time. - Product frames: these define the orientation of a frame relative to a base frame as the product of a specified sequence of frame transformations. All of the factor transformations must be computable by CSPICE. Notation -------- | A lower case letter \`x' is used to designate the cross product operator, as in .. code-block:: text C = A x B Double vertical bars bracketing the name of a vector indicate the norm of the vector: .. code-block:: text ||A|| Throughout this discussion we'll use text enclosed in angle brackets to indicate values to be filled in by the creator of a frame kernel. Examples are: .. code-block:: text Token Replacement Value ------------- ----------------------------------------- 'PRI' or 'SEC' [See discussion of two-vector frames below.] SPICE frame name, .e.g. 'J2000' Integer frame ID code NAIF integer ID for the observing body String indicating aberration correction, e.g.: 'NONE', 'LT', 'XLT', 'LT+S' Required Keywords for Parameterized Dynamic Frames --------------------------------------------------- | All parameterized dynamic frame kernel definitions contain the assignments shown here: .. code-block:: text FRAME_ = FRAME__NAME = FRAME__CLASS = 5 FRAME__CLASS_ID = FRAME__CENTER = FRAME__RELATIVE = FRAME__DEF_STYLE = 'PARAMETERIZED' FRAME__FAMILY = These first five of the assignments are common to all CSPICE frame definitions; the class code 5 indicates that the frame is dynamic. See the section `Guidelines for Frame Specification` in the chapter `Creating a Frame Kernel` above for a detailed discussion of these assignments. The sixth assignment (for keyword FRAME\__RELATIVE) is the `base frame` specification; this indicates the frame the transformation defined by the frame kernel `maps to`: starting with an epoch ET and a state vector S specified relative to the defined frame .. code-block:: text the frame definition determines the 6x6 state transformation matrix XFORM such that the product .. code-block:: text XFORM * S yields the equivalent state specified relative to the base frame at ET. The seventh assignment (for keyword FRAME\__DEF_STYLE) is used to simplify future implementation of other dynamic frame definition styles. Only the value .. code-block:: text 'PARAMETERIZED' is currently supported. The last assignment indicates the frame family. The possible values are .. code-block:: text 'TWO-VECTOR' 'MEAN_EQUATOR_AND_EQUINOX_OF_DATE' 'TRUE_EQUATOR_AND_EQUINOX_OF_DATE' 'MEAN_ECLIPTIC_AND_EQUINOX_OF_DATE' 'EULER' Additional, required frame kernel assignments are a function of the family to which a dynamic frame belongs. These are discussed below. Conditional Keywords for Parameterized Dynamic Frames ------------------------------------------------------ | Rotation State ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | A parameterized dynamic frame definition can specify a frame's `rotation state` as `rotating` or `inertial.` Rotating frames are nominally time-dependent, although it is possible for them to be constant (an Euler frame with all Euler angles constant is an example). When a parameterized dynamic frame is specified as `inertial,` the derivative with respect to time of the transformation between the frame and any inertial frame, for example the J2000 frame, is zero. The rotation between the frame and any inertial frame is still treated as time-dependent. For such a frame F, the call .. code-block:: python xform = sxform( "F", "J2000", t ) yields a 6x6 state transformation matrix `xform` having the structure .. code-block:: text +-----+-----+ | R(t)| 0 | +-----+-----+ | 0 | R(t)| +-----+-----+ where R(t) is the 3x3 rotation matrix that transforms vectors from frame F to the J2000 frame at time `t`. By contrast, when the rotation state of F is `rotating,` `xform` has the structure .. code-block:: text +-----+-----+ | R(t)| 0 | +-----+-----+ |dR/dt| R(t)| +-----+-----+ So, when the rotation state of frame F is `inertial,` velocities are transformed from frame F to J2000 by left-multiplication by R(t) the time derivative of the rotation from F to J2000 is simply ignored. Normally the inertial rotation state makes sense only for slowly rotating frames such as the earth mean equator and equinox of date frame. A parameterized dynamic frame's rotation state is specified via the assignment .. code-block:: text FRAME__ROTATION_STATE = where .. code-block:: text is one of .. code-block:: text 'ROTATING' 'INERTIAL' For frames belonging to the parameterized dynamic frame families .. code-block:: text 'MEAN_EQUATOR_AND_EQUINOX_OF_DATE' 'TRUE_EQUATOR_AND_EQUINOX_OF_DATE' 'MEAN_ECLIPTIC_AND_EQUINOX_OF_DATE' either the rotation state must be specified, or the frame must be frozen (see `Frozen Frames` below). For two-vector and Euler frames, the rotation state specification is optional; these frames are considered to be rotating by default. When the rotation state of a parameterized frame is specified, the frame cannot be frozen; these options are mutually exclusive. Freeze Epoch ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | A parameterized dynamic frame definition can specify a frame as `frozen` at a particular epoch. The rotation between a frozen frame and its base frame is constant; the derivative with respect to time of this rotation is zero. A frozen frame whose base frame is time-varying is still time-varying: it is the relationship between the frozen frame and the base frame that is time-independent. A frame is declared frozen by specifying a `freeze epoch.` This is done via the assignment: .. code-block:: text FRAME__FREEZE_EPOCH = where .. code-block:: text is a TDB calendar date whose format conforms to the SPICE text kernel date format specification. These dates - are unquoted - start with the character .. code-block:: text @ - contain no embedded blanks An example of a template for these calendar strings is .. code-block:: text @YYYY-MON-DD/HR:MN.SEC.### Literal examples include .. code-block:: text @7-MAR-2005 @March-7-2005-3:10:39.221 @2005-MAR-07/3:10:39.221 Note that unlike time strings supported by the CSPICE function :py:meth:`~spiceypy.spiceypy.str2et`, time system tokens such as .. code-block:: text UTC TDT TDB are not supported; times are always assumed to be TDB. For frames belonging to the parameterized dynamic frame families .. code-block:: text 'MEAN_EQUATOR_AND_EQUINOX_OF_DATE' 'TRUE_EQUATOR_AND_EQUINOX_OF_DATE' 'MEAN_ECLIPTIC_AND_EQUINOX_OF_DATE' either the frame must be frozen or the rotation state must be specified, (see `Rotation State` above). For two-vector and Euler frames, the freeze epoch specification is optional; these frames are considered to be time-varying relative to their base frames by default. When a parameterized frame is frozen, the rotation state of the frame cannot be specified; these options are mutually exclusive. Two-Vector Frames ================= | Two-vector frames use two user-specified, non-parallel vectors to define the mutually orthogonal axes of a right-handed reference frame. In a two-vector frame definition, one defining vector is parallel to a specified axis of the reference frame; this vector is called the `primary vector.` The other vector, called the `secondary vector,` defines another axis: the component of the secondary vector orthogonal to the primary vector is parallel to a specified axis of the reference frame. The secondary vector itself need not be, and typically is not, aligned with an axis of the defined frame. Below, we'll call the primary and secondary defining vectors PRI and SEC, and we'll name the axes of the right-handed frame X, Y, and Z. The unit +Z vector is the cross product of the unit +X and +Y vector. In a two-vector frame definition, the vectors PRI and SEC are specified geometrically; for example, PRI could be the position of the earth relative to a spacecraft, and SEC could be defined by the right ascension and declination of a given star in a specified reference frame. In a frame kernel, the vectors PRI and SEC are associated with two members of the set of unit vectors .. code-block:: text { X, -X, Y, -Y, Z, -Z } An example: in this case PRI is associated with -Z and SEC is associated with +X. SEC itself is not parallel to the X axis, but the component of SEC orthogonal to PRI points in the +X direction. The diagram below shows the relationship between PRI, SEC, X, Y, and Z: .. code-block:: text Component of SEC orthogonal to PRI | | ^ v | <-----+--+ \ | | \ +--+ \ | SEC \ | +Z = - PRI / ||PRI|| \ | \ | \ +--+ \| | +X = Y x Z <---------+---+--+ / /| +---/ | /| / / |/| / + | -Z = PRI / ||PRI|| / | / | v v PRI Z x SEC +Y = ----------- ||Z x SEC|| = Z x X By defining PRI and SEC we can create a concrete frame definition. Continuing the above example, we can define a nadir-pointing frame for the Mars Global Surveyor (MGS) spacecraft as follows: .. code-block:: text PRI = Vector from MGS to nearest point on Mars reference ellipsoid Z = -PRI / ||PRI|| SEC = Inertially referenced velocity of MGS relative to Mars Y = Z x SEC / ||Z x SEC|| X = Y x Z For this nadir-pointing frame, -Z is the nadir direction, X points roughly in the direction of the inertially referenced spacecraft velocity, and Y is aligned with the orbital angular velocity vector. By converting the above definition into the frame kernel `keyword=value` format, we can make the definition usable by the CSPICE system. Above, for brevity, we've glossed over a few aspects of the vector definitions. Below we'll discuss in detail all of the elements of two-vector frame specifications. Defining a Two-Vector Frame in a Frame Kernel --------------------------------------------- Kernel Availability ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | In the following discussion, for brevity, we will use the term `computable` to describe frames whose definitions are known to CSPICE and for which kernels have been loaded sufficient to enable computation of the transformations between these frames and their base frames. We'll also call a frame transformation between frames F1 and F2 `computable` if both frames F1 and F2 are computable and kernels have been loaded sufficient to enable computation of the transformation between F1 and F2. For example, the transformation between the J2000 and IAU_TITAN frames is computable once a PCK containing rotational elements for TITAN has been loaded. Specifying the Base Frame ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | When a two-vector frame F is defined with a base frame F_BASE, and when the necessary kernels are loaded, the transformation between F and F_BASE (in both directions) becomes computable by the CSPICE frame subsystem. In addition, for any frame F2 such that the transformation between F2 to F_BASE is computable, the transformation from F2 to F (in both directions) becomes computable. For a two-vector frame, the base frame may be any frame F_BASE such that the transformation between F_BASE and the J2000 reference frame is computable at the time the two-vector frame definition is referenced. Normally for two-vector frames the base frame should be set to 'J2000'; this choice yields optimal run-time efficiency. The assignment is made as follows. .. code-block:: text FRAME__RELATIVE = 'J2000' Base frame specifications are part of the two-vector frame definition because the base frame can be used to control how CSPICE chains together two-vector frames with other frames. However, from a mathematical point of view, two-vector frames are fully defined without reference to a base frame. For example, suppose the two-vector frame F1 is defined by the earth-moon position vector and the earth-sun position vector, and the base frame for F1 is IAU_EARTH. Suppose that the two-vector frame F2 is defined by the same vectors and that the base frame of F2 is J2000. Then, ignoring small round-off errors, the transformation between F1 and F2 is the identity transformation. Base frames should not be confused with other frames occurring in two-vector frame definitions: constant vectors and velocity vectors have associated frames which are also specified by keyword assignments. See the discussion below under the heading `Constant Vectors` and `Velocity Vectors` for details. Specifying the Frame Family ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | Definitions of two-vector frames include the frame family specification: .. code-block:: text FRAME__FAMILY = 'TWO-VECTOR' Further assignments (discussed below) define the primary and secondary vectors and relate these vectors to the frame's axes. Specifying the Rotation state or Freeze Epoch ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | These specifications are optional for two-vector frames. See the section above titled `Conditional Keywords for Parameterized Dynamic Frames` for details. Specifying the Angular Separation Tolerance ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | This specification applies only to two-vector frames and is optional. To diagnose near-degenerate geometry, specifically cases where the defining vectors have angular separation too close to zero or pi radians, users can specify a limit on these angular separations. This is done via the keyword assignment .. code-block:: text FRAME__ANGLE_SEP_TOL = where is the separation limit in radians. If the angular separation of the defining vectors differs from zero or pi radians by less than the specified tolerance, an error will be signaled at run time. When a two-vector frame definition omits specification of an angular separation tolerance, CSPICE uses a default value of one milliradian. Frame Axis Labels ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | The primary defining vector is associated with a frame axis via the assignment .. code-block:: text FRAME__PRI_AXIS =