Source code for optika.radiometry._effective_area
import abc
import dataclasses
import named_arrays as na
import optika
__all__ = [
"AbstractEffectiveAreaModel",
"InterpolatedEffectiveAreaModel",
]
[docs]
@dataclasses.dataclass(eq=False, repr=False)
class AbstractEffectiveAreaModel(
optika.mixins.Printable,
):
"""
An interface describing the effective area of an optical system as a
function of wavelength.
"""
@abc.abstractmethod
def __call__(
self,
wavelength: na.AbstractScalar,
) -> na.AbstractScalar:
"""
The effective area of the optical system at the given wavelength.
Parameters
----------
wavelength
The wavelength at which to evaluate the effective area.
"""
[docs]
@dataclasses.dataclass(eq=False, repr=False)
class InterpolatedEffectiveAreaModel(
AbstractEffectiveAreaModel,
):
"""
An effective area model which linearly interpolates between measured
calibration points.
Linear interpolation is used (rather than a polynomial fit) because the
effective area of a real system has sharp features --- absorption edges,
filter cutoffs, and multilayer reflectivity peaks --- that a polynomial
would fit poorly.
Examples
--------
Interpolate a measured effective area curve and plot the result.
.. jupyter-execute::
import numpy as np
import matplotlib.pyplot as plt
import astropy.units as u
import named_arrays as na
import optika
# A coarse set of calibration measurements
wavelength = na.linspace(100, 1000, axis="wavelength", num=10) * u.AA
area = 10 * np.exp(-(((wavelength - 500 * u.AA) / (150 * u.AA)) ** 2))
area = area * u.cm**2
model = optika.radiometry.InterpolatedEffectiveAreaModel(
wavelength=wavelength,
area=area,
axis_wavelength="wavelength",
)
# Evaluate the model on a finer grid
wavelength_fit = na.linspace(100, 1000, axis="wavelength", num=201) * u.AA
fig, ax = plt.subplots(constrained_layout=True)
na.plt.scatter(wavelength, area, ax=ax, label="calibration")
na.plt.plot(wavelength_fit, model(wavelength_fit), ax=ax, label="interpolated")
ax.set_xlabel(f"wavelength ({na.unit(wavelength):latex_inline})")
ax.set_ylabel(f"effective area ({na.unit(area):latex_inline})")
ax.legend();
"""
wavelength: na.AbstractScalar = dataclasses.MISSING
"""The wavelength of each calibration point."""
area: na.AbstractScalar = dataclasses.MISSING
"""The measured effective area at each calibration point."""
axis_wavelength: str = dataclasses.MISSING
"""The logical axis corresponding to changing wavelength."""
def __call__(
self,
wavelength: na.AbstractScalar,
) -> na.AbstractScalar:
return na.interp(
wavelength,
self.wavelength,
self.area,
axis=self.axis_wavelength,
)