Source code for irfpy.cena.fov
r''' fov module is for Chap 3. in the CENA FM calibration report.
The :ref:`CENA calibration report issue 1 rev 1 <cenacalrep>` is implemented here.
The module treats Chapter 3: Sensor properties.
A simple use of the module can be found as a script of :mod:`cena_visualize_fov`.
Conversion between |theta| |phi| system to a vector is implemented in :mod:`irfpy.cena.frame` module.
See also :ref:`frame_conversion`.
Definition of |theta| and |phi| is as follows.
Primary axis is -*z* axis.
|theta| is measured from *xy* plane and positive in -*z* axis.
In other word, this is a co-latitude measured from -*z* axis.
|phi| is measured from *y* axis (strictly speaking *yz* plane) and
positive toward *x* axis.
See Figure 1.1 in :ref:`cenacalrep`.
'''
import math
import numpy as np
[docs]def shape_of_response(n, theta, phi):
''' Return the shape of response.
|theta| is elevation angle and |phi| is the azimuthal angle in degrees.
|theta| should be -90 to 90, and |phi| should be -180 to 180.
*n* is the channel ID from 0 to 6.
'''
if n < 0 or n > 6:
raise IndexError('*n* should be between 0 and 6')
if theta < -90 or theta > 90:
raise IndexError('*theta* should be between -90 and 90')
if phi < -180 or phi > 180:
raise IndexError('*phi* should be between -180 and 180')
sig = azim_pix_fwhm(n) / 2.35
yet = elev_pix_fwhm(n) / 2.35
phi_c = azim_pix_center(n)
theta_c = elev_pix_center(n)
coeff = - (((phi - phi_c) ** 2) / (2 * sig * sig)
+ ((theta - theta_c) ** 2) / (2 * yet * yet))
return math.exp(coeff)
[docs]def pixel_shape(n, elevresolution=0, azimresolution=0, resolution=None, fill=False):
r''' Return an array of the pixel edge angle of its FWHM.
:param n: Channel number. 0 to 6.
:param azimresolution: Azimuthal resolution. Number of division in azimuthal direction.
:param elevresolution: Elevation resolution. Number of division in elevation direction.
:param resolution: Resolution. Overwrite ``azimresolution`` and ``elevresolution``.
:param fill: If true, the first point is added to the end.
:returns: A tuple of 2 numpy array. Array of :math:`\theta` and array of :math:`\phi`.
The number of elements is ``4+2*azimresolution+2*elevresolution``.
If fill is True, one more element is added.
However, it is recommend to check the number after you get the array.
>>> pix0 = pixel_shape(0, azimresolution=50, elevresolution=3)
>>> print(len(pix0[0]), len(pix0[1]))
110 110
'''
if resolution is not None:
azimresolution = resolution
elevresolution = resolution
azimc = azim_pix_center(n)
elevc = elev_pix_center(n)
azimw = azim_pix_fwhm(n)
elevw = elev_pix_fwhm(n)
azim0 = azimc - azimw / 2.
elev0 = elevc - elevw / 2.
azim1 = azimc + azimw / 2.
elev1 = elevc + elevw / 2.
azndiv = azimresolution + 1
dazim = azimw / azndiv
elndiv = elevresolution + 1
delev = elevw / elndiv
az_list = []
el_list = []
for idiv in range(elndiv):
az_list.append(azim1)
el_list.append(elev0 + idiv * delev)
for idiv in range(azndiv):
az_list.append(azim1 - idiv * dazim)
el_list.append(elev1)
for idiv in range(elndiv):
az_list.append(azim0)
el_list.append(elev1 - idiv * delev)
for idiv in range(azndiv):
az_list.append(azim0 + idiv * dazim)
el_list.append(elev0)
if fill:
az_list.append(az_list[0])
el_list.append(el_list[0])
return np.array(el_list), np.array(az_list)
[docs]def azim_pix_center(n):
''' Returns the azimuth (|phi|) center in degrees for the pixel *n*.
Implements equation (3.2), -19.06*n + 57.19
'''
if n < 0 or n > 6:
raise IndexError('*n* should be between 0 and 6')
return -19.06 * n + 57.19
[docs]def azim_pix_fwhm(n):
''' Returns the FWHM of the azimuthal directions (|phi|) in degrees.
Implements equation (3.3). Indeed it does not depend on *n*,
45.0 degrees.
'''
return 45.0
[docs]def elev_pix_center(n):
''' Returns the elevation center (|theta|) in degrees for the pixel *n*.
Implements equation (3.4). It does not indeed depend on *n*:
-6.05 degrees.
'''
return -6.05
[docs]def elev_pix_fwhm(n):
''' Returns the FWHM of the elevation (|theta|) directions in degrees.
Implements equation (3.5). Independent of *n*, 6.44 is returned.
'''
return 6.44
[docs]def solid_angle(n):
r''' Returns the approximate soliad angle.
Equation (3.8) gives the definition.
.. math::
\Delta\Omega_n \approx FWHM_{\phi,n} \cdot FWHM_{\theta,n}
>>> print('%.3f' % solid_angle(0))
0.088
'''
elev = elev_pix_fwhm(n) * math.pi / 180.
azim = azim_pix_fwhm(n) * math.pi / 180.
return elev * azim
[docs]def infov(theta, phi):
r""" A simple FOV envelope checker.
:param theta: The |theta| angle(s), from -90 to 90 in degrees. Looking direction.
:param phi: The |phi| angle(s), from -180 to 180 in degrees. Looking direction.
>>> infov(0, 0)
True
>>> infov(5, 0) # Theta=5, False
False
>>> infov(-5, 0)
True
>>> infov([-6, -6, -6, -6, -6], [-180, -90, 0, 90, 180])
array([False, False, True, False, False])
"""
_theta = np.array(theta)
_phi = np.array(phi)
theta_cond = np.logical_and(_theta >= -15, _theta <= 0)
phi_cond = np.logical_and(_phi >= -75, _phi <= 75)
return np.logical_and(theta_cond, phi_cond)