irfpy.mima.fov

FOV module for IMA

SimpleFOV provides the simplest fov geometry, namely the equally separted solid angle. This is independent of the energy. So that in the low energy part it does not provide good vector.

IMA Frame

There is always a confusion. In SPICE, there are two (not identical) frames: MEX_ASPERA_IMA and MEX_ASPERA_IMAS. In this module, MEX_ASPERA_IMAS to be the IMA frame, since most of the internal document looks to follow the definition of IMAS. Anyway both are rigidly fixed, but the axis is different (also focul point).

From the MEX_V11.TF, the following is the definition.

-Z s/c side view ("main engine" side):
--------------------------------------

                             +Xsc
    -Y Solar Array               ^              +Y Solar Array
   ._________________     .______|______.     .________________.
   |                 \    |      |      |    /                 |
   |                  \   |      |      |   /                  |
   |                   |  |      |+Zsc  |  |                   |
   |           +Zimas  |+Yimas   x------->o|                   |
   |           +Xima   |+Zima         +Ysc .                   |
   |                <----o  +Zimau      |   \                  |
   ._________________/  <----o__________.    \_________________.
                  +Ximau |   |'     `.
                         V  /|________\
                     +Ximas  V        HGA
                     +Yima   +Yimau

                                       +Zsc is into the page
                                     +Zima, +Zimau, and +Yimas
                                        are out of the page

-Z s/c side view ("main engine" side) -- zoom in:
-------------------------------------------------

                        --                         ^ +Xsc
                       |  \                        |
                       |   \__                     |
                       |      \_________           |
                       |                \          |
                       |                 \         x------->
             IMA       |._____________.   \     +Zsc      +Ysc
            Aperture   || o         o |    \
                .___________________. |     \____
       +Zimas   | |  +Yimas         | |          \
       +Xima    | |  +Zima          | |           \
            <-------o |             | |            \
                | | | |             | |   IMA       |
                | | | |             | | Mounting     \
                .___|_______________. |   plate      |
                    |  || o <-------o |              |
             +Ximas V  |. +Ximau ___|_.             /
             +Yima     |            |               | "Main Engine"
                       .____________|_______________/      Deck
                                    |
                             +Yimau V

In addition, the instrument numbering is as follows:

This diagram illustrates in-plane (azimuthal) IMA sector layout:

                        +Yimas
                      ^ +Zima
                      |                        A# indicate the azimuthal
                  V5  |  V4                      sector "#" position in
             V6   ....|....   V3                  the sensor assembly.
               .' A13 | A12 `.
          V7 .' A14   |    A11`. V2            V# indicate the "#" sector
            . A15     |      A10.                     view direction.
        V8 .          |          . V1
           .A0        |        A9.     +Ximas      For example, for
           .          o--------------> +Yima     Sector "11" the view
           .A1       / +Zimas  A8.              direction is the vector
        V9 .        /  +Xima     . V0             emanating from the
            .A2    /          A7.               aperture center through
         V10 .    /         A6 .  V15            the point designated
              `. / A4   A5   .'                         by "V11".
              V11 ......... ' V14
               /   V12  V13
              V
    Azimuthal sector "11"
       view direction



This diagram illustrates cross-plane (polar) IMA sector layout:

                    +Yimas
                    +Zima   Polar Sector "3"
                      ^         ^ view dir.     A# indicate the polar
                   V8 | V7     /                 sector "#" position in
                 .----|----.  V3                  the sensor assembly.
         V15  ,-'   P8|P7   `/.   V0
            .'        |     P3 `.
           `.P15      |    /  P0.'             V# indicate the "#" sector
             `.       |   /   .'                    view direction.
               `.     |  /  .'
                 `.   | / .'                    For example, for polar
                   `. |/+Ximas                   Sector "3" the view
       <-------------`o'+Yima                  direction is the vector
     +Zimas         .' `.                        emanating from the
     +Xima        .'     `.                    aperture center through
                .'         `.                     the point designated
              .'             `.                       by "V2".
            .'P15            P0`.
            `.                 .'
          V15 `-.   P8 P7   ,-'  V0
                 `---------'
                   V8   V7

See also http://aspera-3.irf.se/Members/futaana/illustration/FovAspera3.png

irfpy.mima.fov.get_azimuth_angle(azim_nr, direction='look')[source]

Return the azimuthal angle.

The origin is -x direction of s/c frame. Increase toward -z s/c. Note that the definition is 180-degrees opposite from the definition of IMA Bible.

Parameters
  • azim_nr – Azimuthal number, extended to floating point without bounds.

  • direction – The direction of azimuth angle.

Returns

Angle.

class irfpy.mima.fov.SimpleFOV[source]

Bases: object

Field of view for equally spaced solid angle.

The FOV class reporesents the simplest geometric FOV for MEX/IMA. The IMAS frame, according to SPICE, is used. The benefit of using geometric FOV is the simplest handling, intuitive understanding, no dependence on energy or mode, allowance of floating-point elevation steps, quick implementation and easily vectorized. In addition, inverse solution (from vector knowing sensor ID) can be uniquely determined. The drawback is that the FOV does not (necessarily) represent the actual IMA FOV. Particularly for low energy steps, the elevation scan did not apply, so that the diverge is not accepatble for serious science. In this case, one have to use TableFOV.

viewvector_imasframe(azim_nr, elev_nr)[source]

Return the viewing vector for IMAS frame

For azimuth, viewing channel 0 is -11.25 deg from +Ximas toward +Yimas (so that -Y direction in principle). Direction 1 is +11.25 deg. Thus azimuth angle is \(-11.25 + 22.5 \times az\)

For elevation, the viewing angle for 0 is -42.1875 deg from X,Yimas plane toward +Zimas Increasing number will increase by 5.625 deg. Thus, elevation angle is \(-42.1875 + 5.625 \times el\).

>>> fov = SimpleFOV()

The azimuth 0.5 and elevation 7.5 specifies the x direction looking.

>>> print(fov.viewvector_imasframe(0.5, 7.5))    
[1. 0. 0.]

If you change the azimuth to 4.5, this is y axis.

>>> viewdir = fov.viewvector_imasframe(4.5, 7.5)
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(viewdir))
0.00 1.00 0.00

The view vector for the elevation -0.5 is the loweredge, namely, -45 degrees in azimuth.

>>> viewdir = fov.viewvector_imasframe(0.5, -0.5)
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(viewdir))
0.71 0.00 -0.71

If the elevation step -10 is given, this is out of the elevation range. Masked array is returned.

>>> viewdir = fov.viewvector_imasframe(0.5, -10)
>>> print(viewdir)
[-- -- --]

The last sample shows the masked array, when the elevtion number is out of range. The azimuthal number is periodic.

>>> viewdir = fov.viewvector_imasframe(16.5, 7.5)   # Should be the same as (0.5, 7.5), ie, x axis
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(viewdir))
1.00 -0.00 0.00

One can get the velocity vector from velocityvector_imasframe(), which is just a negated array of viewvector_imasframe().

>>> viewdir = fov.viewvector_imasframe(1, -0.5)
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(viewdir))
0.69 0.14 -0.71
>>> veldir = fov.velocityvector_imasframe(1, -0.5)
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(veldir))
-0.69 -0.14 0.71

If the shapes for the arguments are the same, you can use arrays as input.

elevation_angle(elev_nr, direction='look')[source]

Return the elevation angle.

azimuth_angle(azim_nr, direction='look')[source]
velocityvector_imasframe(azim_nr, elev_nr)[source]

Return the velocity vector for IMAS frame

Mathematically identical to minus of viewvector_imasframe().

numbering_imasframe(viewvector)[source]

Return the (az, el) tuple corresponding view vector.

The viewvecotr in IMAS frame is converted to the numbering of az and el. Here, az should range from -0.5 to 15.5. el should range from -8.5 to 23.5, while -0.5 to 15.5 is only detectable.

>>> fov = SimpleFOV()
>>> viewvec = [1, 0, 0]
>>> print(fov.numbering_imasframe(viewvec))  
[0.5 7.5]
>>> viewvec = [np.sqrt(0.5), 0, -np.sqrt(0.5)]
>>> print(fov.numbering_imasframe(viewvec))  
[ 0.5 -0.5]
>>> viewvec = [0, 1, 0]
>>> print(fov.numbering_imasframe(viewvec))  
[4.5 7.5]
>>> viewvec = [0, 0, 1]
>>> print(fov.numbering_imasframe(viewvec)[1])
23.5

You may give (3, N) shaped array. Then, you may get (2, N) shaped array, with (az, el) for axis 0.

>>> viewvec = [[1, 0, 1, 0], [0, 1, 0, -1], [-1, -1, 1, 1]]
>>> print(fov.numbering_imasframe(viewvec))
[[ 0.5   4.5   0.5  12.5]
 [-0.5  -0.5  15.5  15.5]]
shadow_mask()[source]

Return the pre-defined angular mask.

Returns

(A16, P16) shaped boolean array. True for channel with mask, False for free mask.

Discussion in Futaana et al., 2010. Phobos paper.

>>> mask_table = SimpleFOV().shadow_mask()
>>> mask_table.shape
(16, 16)
>>> mask_table[0, 0]    # Azimuth=0, elevation=0 is shadowed by SC
True
>>> mask_table[2, 10]   # Azimuth=2, elevation=10 is free
False
>>> mask_table[12, :].all()   # For azimuth=12, all elevation is blocked.
True
shadow_mask_corners(phase=0)[source]

Return corner index as a (N, 2)-shaped array.

The corner index, in the (N, 2)-shaped array. By connecting the element of array, you may get the envelope of the shadow mask.

Parameters

phase – The phase of the index. If the phase is 0 (default), the azimuthal index varies from (-8.5 to 1.5). If the phase 1 1, the azimuthal index varies from (7.5 to 17.5). This is prepared since the envelope crosses the boundary between the channels of 15 and 0.

>>> fov = SimpleFOV()
>>> corners = fov.shadow_mask_corners()
>>> print(corners.shape)
(21, 2)
>>> print(corners[0])   # The start point of the envelope, which is azimuth -8.5 and elevation -0.5.
[-8.5 -0.5]
class irfpy.mima.fov.TableFOV[source]

Bases: object

FOV information from the table provided from Andrei

The information is from ima_info.nc file provided from Andrei in Nov 2014. The FOV information is in ImaElev variable, with the size of (ImaNTables=4, ImaEnerDim=96, ImaElevDim=16).

Therefore, the viewvector_imasframe() or other method should take table_id argument.

  • table_id=0, Default table in PROM

  • table_id=1, updated in 2006. in EEPROM=0

  • table id=2, updated in 2009. in EEPROM=15

  • table id=3, for fast scan. EEPROM=13

In addition, energy and elevation steps should be given by the integer with the range 0–95 and 0–15 respectively. It is allowed to have float values for azimuthal directions.

>>> fov = TableFOV()  # Create table based FOV.
>>> simplefov = SimpleFOV()  # Create geometric based FOV for comparison.

For table=0, azimuth=0.5, elevation=10, and energy step = 15, the looking direction in IMA frame is obtained by as follows.

>>> print(fov.viewvector_imasframe(0, 0.5, 10, 15))  
[0.977415...  0.          0.21132... ]

You can compare with the results from the simple FOV.

>>> print(simplefov.viewvector_imasframe(0.5, 10))  
[0.97003... 0.         0.24298...]

If the view angle does not make sense, [nan, nan, nan] array will be returend.

>>> print(fov.viewvector_imasframe(0, 0.5, 3, 80))   
[nan nan nan]
>>> viewdir = fov.viewvector_imasframe(1, 4.5, 0, 21)  # This is the lower edge of el=0, ie, around -45 deg.
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(viewdir))
0.00 0.74 -0.67

One can get the velocity vector from velocityvector_imasframe(), which is just a negated array of viewvector_imasframe().

>>> veldir = fov.velocityvector_imasframe(1, 4.5, 0, 21)
>>> print('{0[0]:.2f} {0[1]:.2f} {0[2]:.2f}'.format(veldir))
-0.00 -0.74 0.67
promsection_to_tableid = {0: 0, 'PROM': 0, 1: 1, 'EEPROM_00': 1, 16: 2, 'EEPROM_15': 2, 15: 2, 'EEPROM_14': 2, 14: 3, 'EEPROM_13': 3}

Dictionary showing the PROM section index to the table ID.

PROM-section is the booting software section. It defines the energy / direction table. MEX/IMA has 1 PROM and 16 EEPROM (0 to 15). PROM is representedted by 0, while EEPROM is represented with increment by 1 (PROM is 0, EEPROM_00 is 1, EEPROM_01 is 2, and so on).

On the other hand, some ground software uses “table_id”, where irfpy follows this custom.

Todo

A new implementation directly handle the table according to the data (ImaPacket) is needed. Similar implementation in irfpy.mima.energy

viewvector_imasframe(table_id, azim_nr, elev_nr, ene_nr)[source]

View vector in IMAS frame is returned.

Parameters
  • table_id – Table number. So far 0 to 3 is supported.

  • azim_nr – Azimuthal step

  • elev_nr – Elevation step

  • ene_nr – Energy step

Returns

View vector in IMAS frame. If no viewing direction is defined, [nan, nan, nan] is returned.

Vectorization is not supported.

elevation_angle(table_id, elev_nr, ene_nr, direction='look')[source]
azimuth_angle(azim_nr, direction='look')[source]
velocityvector_imasframe(table_id, azim_nr, elev_nr, ene_nr)[source]
numbering_imasframe(viewvector)[source]

Numbering in IMAS frame will be returned.

shadow_mask()[source]

This method is not implemented. Use shadow_mask3d().

shadow_mask3d(table_id)[source]

Return a table, with a shape of (A16, E96, P16), where the shadow_mask is embedded.

Parameters

table_id – The table ID

Returns

(A16, E96, P16) boolean array showing the shadow mask. True is masked.

>>> tableFov = TableFOV()
>>> mask0 = tableFov.shadow_mask3d(0)
>>> print(mask0.shape)
(16, 96, 16)
>>> print(mask0[10, 32, 5])      # Azimuth=10, energy=32, elevation=5
True
>>> print(mask0[7, 32, 5])      # Azimuth=7, energy=32, elevation=5
False
elev_table

Elevation table in np.array format.

The elevation table read from the ima_info.nc. The shape is (ntalbe=4, enestep=96, elevstep=16)

irfpy.mima.fov.doctests()[source]