Skip to content

Commit

Permalink
Added optika.sensors.IdealImagingSensor class. (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
byrdie authored Apr 15, 2024
1 parent ab2783b commit fea0419
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 2 deletions.
2 changes: 2 additions & 0 deletions optika/sensors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)
from ._sensors import (
AbstractImagingSensor,
IdealImagingSensor,
AbstractCCD,
)

Expand All @@ -29,5 +30,6 @@
"E2VCCD97Material",
"E2VCCDAIAMaterial",
"AbstractImagingSensor",
"IdealImagingSensor",
"AbstractCCD",
]
75 changes: 73 additions & 2 deletions optika/sensors/_sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
"""

from typing import TypeVar
import abc
import dataclasses
import astropy.units as u
import named_arrays as na
import optika

__all__ = [
"AbstractImagingSensor",
"IdealImagingSensor",
"AbstractCCD",
]


MaterialT = TypeVar("MaterialT", bound=optika.materials.AbstractMaterial)


@dataclasses.dataclass(eq=False, repr=False)
class AbstractImagingSensor(
optika.surfaces.AbstractSurface[
None,
Expand All @@ -23,14 +29,79 @@ class AbstractImagingSensor(
None,
],
):
"""
An interface describing an imaging sensor that can be used as the last
surface in an optical system.
"""

@property
def sag(self) -> None:
return None
def sag(self) -> optika.sags.AbstractSag:
return optika.sags.NoSag()

@property
def rulings(self) -> None:
return None

@property
@abc.abstractmethod
def width_pixel(self) -> u.Quantity | na.AbstractCartesian2dVectorArray:
"""
The physical size of each pixel on the sensor.
"""

@property
@abc.abstractmethod
def num_pixel(self) -> na.Cartesian2dVectorArray[int, int]:
"""
The number of pixels along each axis of the sensor.
"""

@property
def aperture(self):
"""
The light-sensitive aperture of the sensor.
"""
return optika.apertures.RectangularAperture(
half_width=self.width_pixel * self.num_pixel / 2,
)


@dataclasses.dataclass(eq=False, repr=False)
class IdealImagingSensor(
AbstractImagingSensor,
):
"""
An idealized imaging sensor with perfect efficiency and no noise sources.
"""

name: None | str = None
"""The human-readable name of this sensor."""

width_pixel: u.Quantity | na.AbstractCartesian2dVectorArray = 0 * u.um
"""The physical size of each pixel on the sensor."""

num_pixel: na.Cartesian2dVectorArray[int, int] = None
"""The number of pixels along each axis of the sensor."""

aperture_mechanical: optika.apertures.RectangularAperture = None
"""The shape of the physical substrate supporting the sensor."""

is_field_stop: bool = False
"""A flag controlling whether this sensor is the field stop for the system."""

is_pupil_stop: bool = False
"""A flag controlling whether this sensor is the pupil stop for the system."""

transformation: None | na.transformations.AbstractTransformation = None
"""The position and orientation of the sensor in the global coordinate system."""

kwargs_plot: None | dict = None
"""Extra keyword arguments to pass to :meth:`plot`"""

@property
def material(self) -> optika.materials.AbstractMaterial:
return optika.materials.Vacuum()


class AbstractCCD(
AbstractImagingSensor[MaterialT],
Expand Down
32 changes: 32 additions & 0 deletions optika/sensors/_tests/test_sensors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest
import numpy as np
import astropy.units as u
import named_arrays as na
import optika
from optika._tests.test_surfaces import AbstractTestAbstractSurface


class AbstractTestAbstractImagingSensor(
AbstractTestAbstractSurface,
):
def test_num_pixel(self, a: optika.sensors.AbstractImagingSensor):
result = a.num_pixel
assert isinstance(result, na.AbstractCartesian2dVectorArray)
assert np.issubdtype(na.get_dtype(result.x), int)
assert np.issubdtype(na.get_dtype(result.y), int)


@pytest.mark.parametrize(
argnames="a",
argvalues=[
optika.sensors.IdealImagingSensor(
name="test sensor",
width_pixel=15 * u.um,
num_pixel=na.Cartesian2dVectorArray(2048, 1024),
)
],
)
class TestIdealImagingSensor(
AbstractTestAbstractImagingSensor,
):
pass

0 comments on commit fea0419

Please sign in to comment.