getframes 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. getframes/__about__.py +4 -0
  2. getframes/__init__.py +91 -0
  3. getframes/analysis/__init__.py +18 -0
  4. getframes/analysis/apertures.py +92 -0
  5. getframes/analysis/ptc.py +109 -0
  6. getframes/calibrate.py +182 -0
  7. getframes/camera.py +649 -0
  8. getframes/cli.py +214 -0
  9. getframes/config.py +420 -0
  10. getframes/dataset.py +294 -0
  11. getframes/frame.py +107 -0
  12. getframes/noise.py +637 -0
  13. getframes/observation.py +162 -0
  14. getframes/presets/__init__.py +90 -0
  15. getframes/presets/data/__init__.py +3 -0
  16. getframes/presets/data/andor_ikon_m934.toml +22 -0
  17. getframes/presets/data/andor_ixon_ultra_888.toml +22 -0
  18. getframes/presets/data/generic_ccd.toml +18 -0
  19. getframes/presets/data/generic_cmos.toml +18 -0
  20. getframes/presets/data/generic_eapd.toml +20 -0
  21. getframes/presets/data/generic_emccd.toml +20 -0
  22. getframes/presets/data/generic_scmos.toml +21 -0
  23. getframes/presets/data/hamamatsu_orca_fusion.toml +25 -0
  24. getframes/presets/data/leonardo_saphira.toml +32 -0
  25. getframes/presets/data/zwo_asi2600mm.toml +20 -0
  26. getframes/py.typed +0 -0
  27. getframes/scene/__init__.py +51 -0
  28. getframes/scene/optics.py +180 -0
  29. getframes/scene/photometry.py +311 -0
  30. getframes/scene/psf.py +371 -0
  31. getframes/scene/scene.py +205 -0
  32. getframes/scene/sources.py +683 -0
  33. getframes/scene/thermal.py +114 -0
  34. getframes/scene/wcs.py +110 -0
  35. getframes/spectral.py +449 -0
  36. getframes-2.0.0.dist-info/METADATA +218 -0
  37. getframes-2.0.0.dist-info/RECORD +40 -0
  38. getframes-2.0.0.dist-info/WHEEL +4 -0
  39. getframes-2.0.0.dist-info/entry_points.txt +2 -0
  40. getframes-2.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,162 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """Time as a first-class dimension: pointing models and the :class:`Observation`.
3
+
4
+ A single :class:`~getframes.frame.Frame` is a snapshot. An :class:`Observation` is
5
+ a *sequence* of frames of one scene over time, produced by
6
+ :meth:`getframes.Camera.observe_series`. It bundles:
7
+
8
+ * the realised :class:`~getframes.frame.Frame` stack,
9
+ * the per-frame timestamps,
10
+ * the realised per-frame pointing offsets (from a :class:`Pointing` model), and
11
+ * an :class:`ObservationTruth` light curve --- the injected, noise-free signal of
12
+ each named source at each frame, for validating photometry against ground truth.
13
+
14
+ Time variability itself lives on the sources (a
15
+ :class:`~getframes.scene.sources.LightCurve` on a
16
+ :class:`~getframes.scene.sources.PointSource`); the observation only samples them.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from collections.abc import Iterator, Sequence
22
+ from dataclasses import dataclass, field
23
+ from typing import TYPE_CHECKING
24
+
25
+ import numpy as np
26
+
27
+ if TYPE_CHECKING:
28
+ from numpy.typing import NDArray
29
+
30
+ from .frame import Frame
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class Pointing:
35
+ """A per-frame pointing model: jitter, slow drift, and a programmed dither.
36
+
37
+ The three components combine additively into a whole-field offset applied to
38
+ every source in the scene at each frame. Offsets are specified in arcseconds
39
+ (converted to pixels with the scene's plate scale) so the model is independent
40
+ of the detector sampling.
41
+
42
+ Parameters
43
+ ----------
44
+ jitter_arcsec:
45
+ RMS of a per-frame Gaussian offset drawn independently for each axis and
46
+ each frame. Models random tracking jitter and atmospheric tip-tilt / image
47
+ motion (e.g. for AO sub-apertures). ``0`` disables it.
48
+ drift_arcsec_per_s:
49
+ A constant ``(vx, vy)`` velocity giving a slow linear drift; the offset at
50
+ time ``t`` is ``(vx * t, vy * t)``. Models tracking error / field rotation
51
+ creep.
52
+ dither_arcsec:
53
+ An optional sequence of programmed ``(dx, dy)`` offsets, cycled by frame
54
+ index (frame ``i`` uses entry ``i % len``). Models a deliberate dither
55
+ pattern. ``None`` for no dither.
56
+ """
57
+
58
+ jitter_arcsec: float = 0.0
59
+ drift_arcsec_per_s: tuple[float, float] = (0.0, 0.0)
60
+ dither_arcsec: Sequence[tuple[float, float]] | None = None
61
+
62
+ def __post_init__(self) -> None:
63
+ if self.jitter_arcsec < 0:
64
+ raise ValueError("jitter_arcsec must be non-negative.")
65
+
66
+ @property
67
+ def is_static(self) -> bool:
68
+ """Whether this model never moves the field (a no-op pointing)."""
69
+ return (
70
+ self.jitter_arcsec == 0.0
71
+ and self.drift_arcsec_per_s == (0.0, 0.0)
72
+ and not self.dither_arcsec
73
+ )
74
+
75
+ def offset_pixels(
76
+ self,
77
+ frame_index: int,
78
+ time_s: float,
79
+ plate_scale_arcsec_per_pixel: float,
80
+ rng: np.random.Generator,
81
+ ) -> tuple[float, float]:
82
+ """The realised ``(dx, dy)`` offset in pixels for one frame.
83
+
84
+ Combines drift (deterministic in ``time_s``), the cycled dither entry, and a
85
+ fresh Gaussian jitter draw, then converts arcseconds to pixels.
86
+ """
87
+ dx_as = self.drift_arcsec_per_s[0] * time_s
88
+ dy_as = self.drift_arcsec_per_s[1] * time_s
89
+ if self.dither_arcsec:
90
+ ddx, ddy = self.dither_arcsec[frame_index % len(self.dither_arcsec)]
91
+ dx_as += ddx
92
+ dy_as += ddy
93
+ if self.jitter_arcsec > 0:
94
+ dx_as += float(rng.normal(0.0, self.jitter_arcsec))
95
+ dy_as += float(rng.normal(0.0, self.jitter_arcsec))
96
+ return dx_as / plate_scale_arcsec_per_pixel, dy_as / plate_scale_arcsec_per_pixel
97
+
98
+
99
+ @dataclass(frozen=True)
100
+ class ObservationTruth:
101
+ """The noise-free ground truth of an :class:`Observation`.
102
+
103
+ Attributes
104
+ ----------
105
+ times_s:
106
+ The frame timestamps, in seconds from the start of the observation,
107
+ shape ``(n_frames,)``.
108
+ light_curve:
109
+ Per-source injected signal: a mapping from source name to an array of the
110
+ noise-free incident photons collected from that source in each frame
111
+ (photon rate x exposure, post-optics, pre-quantum-efficiency), shape
112
+ ``(n_frames,)``. This is the true light curve to validate measured
113
+ photometry against. Unnamed sources are keyed ``"source_{index}"``.
114
+ """
115
+
116
+ times_s: NDArray[np.float64]
117
+ light_curve: dict[str, NDArray[np.float64]]
118
+
119
+
120
+ @dataclass(frozen=True)
121
+ class Observation:
122
+ """A reproducible stack of frames of one scene over time.
123
+
124
+ Returned by :meth:`getframes.Camera.observe_series`. It is iterable and
125
+ indexable over its :attr:`frames`, so existing ``for frame in obs:`` style code
126
+ keeps working, while :attr:`truth`, :attr:`times_s`, and :attr:`offsets_pixels`
127
+ expose the time and pointing information.
128
+
129
+ Attributes
130
+ ----------
131
+ frames:
132
+ The realised science :class:`~getframes.frame.Frame` stack, in time order.
133
+ times_s:
134
+ Frame timestamps in seconds, shape ``(n_frames,)``.
135
+ offsets_pixels:
136
+ The realised pointing offset ``(dx, dy)`` applied to each frame, in pixels,
137
+ shape ``(n_frames, 2)``.
138
+ truth:
139
+ The :class:`ObservationTruth` light curve, or ``None`` when truth was not
140
+ requested.
141
+ """
142
+
143
+ frames: list[Frame]
144
+ times_s: NDArray[np.float64]
145
+ offsets_pixels: NDArray[np.float64]
146
+ truth: ObservationTruth | None = field(default=None)
147
+
148
+ def __iter__(self) -> Iterator[Frame]:
149
+ return iter(self.frames)
150
+
151
+ def __len__(self) -> int:
152
+ return len(self.frames)
153
+
154
+ def __getitem__(self, index: int) -> Frame:
155
+ return self.frames[index]
156
+
157
+ def __repr__(self) -> str:
158
+ cam = self.frames[0].metadata.get("camera", "?") if self.frames else "?"
159
+ return f"Observation(n_frames={len(self.frames)}, camera={cam!r})"
160
+
161
+
162
+ __all__ = ["Observation", "ObservationTruth", "Pointing"]
@@ -0,0 +1,90 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """Built-in library of camera/detector presets.
3
+
4
+ Presets are stored as TOML files in :mod:`getframes.presets.data`. They are loaded
5
+ lazily and cached. Add a new camera by dropping a ``<name>.toml`` file into that
6
+ directory (see the existing files for the schema) — no code changes required.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import sys
12
+ from functools import cache, lru_cache
13
+ from typing import TYPE_CHECKING, Any
14
+
15
+ if sys.version_info >= (3, 11):
16
+ import tomllib
17
+ else: # pragma: no cover - exercised only on 3.10
18
+ import tomli as tomllib
19
+
20
+ from importlib import resources
21
+
22
+ if TYPE_CHECKING:
23
+ from ..config import CameraConfig
24
+
25
+ _DATA_PACKAGE = "getframes.presets.data"
26
+
27
+
28
+ @lru_cache(maxsize=1)
29
+ def _preset_files() -> dict[str, str]:
30
+ """Map preset slug -> resource filename for every bundled ``*.toml``."""
31
+ files: dict[str, str] = {}
32
+ for entry in resources.files(_DATA_PACKAGE).iterdir():
33
+ if entry.name.endswith(".toml"):
34
+ files[entry.name[: -len(".toml")]] = entry.name
35
+ return dict(sorted(files.items()))
36
+
37
+
38
+ def available_presets() -> list[str]:
39
+ """Return the sorted list of available preset names.
40
+
41
+ >>> from getframes import available_presets
42
+ >>> "andor_ikon_m934" in available_presets()
43
+ True
44
+ """
45
+ return list(_preset_files())
46
+
47
+
48
+ def preset_info() -> list[dict[str, Any]]:
49
+ """Return lightweight descriptors (name, manufacturer, model, sensor_type) for each preset."""
50
+ info: list[dict[str, Any]] = []
51
+ for slug in available_presets():
52
+ data = _read_preset(slug)
53
+ info.append(
54
+ {
55
+ "preset": slug,
56
+ "name": data.get("name", slug),
57
+ "manufacturer": data.get("manufacturer"),
58
+ "model": data.get("model"),
59
+ "sensor_type": data.get("sensor_type"),
60
+ }
61
+ )
62
+ return info
63
+
64
+
65
+ @cache
66
+ def _read_preset(name: str) -> dict[str, Any]:
67
+ files = _preset_files()
68
+ if name not in files:
69
+ available = ", ".join(available_presets()) or "(none found)"
70
+ raise KeyError(f"Unknown preset {name!r}. Available presets: {available}.")
71
+ raw = resources.files(_DATA_PACKAGE).joinpath(files[name]).read_bytes()
72
+ return tomllib.loads(raw.decode("utf-8"))
73
+
74
+
75
+ def load_preset(name: str) -> CameraConfig:
76
+ """Load a preset by name and return a :class:`~getframes.config.CameraConfig`.
77
+
78
+ Parameters
79
+ ----------
80
+ name:
81
+ A preset slug, e.g. ``"andor_ikon_m934"``. See :func:`available_presets`.
82
+ """
83
+ from ..config import CameraConfig
84
+
85
+ data = dict(_read_preset(name))
86
+ data.setdefault("name", name)
87
+ return CameraConfig.from_dict(data)
88
+
89
+
90
+ __all__ = ["available_presets", "load_preset", "preset_info"]
@@ -0,0 +1,3 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """Bundled preset data files (TOML). This package exists so the ``*.toml`` files
3
+ are importable via :mod:`importlib.resources`."""
@@ -0,0 +1,22 @@
1
+ # Andor iKon-M 934 — deep-cooled scientific CCD
2
+ # Values are representative of published specifications; verify against your
3
+ # own characterisation for quantitative work.
4
+ name = "Andor iKon-M 934"
5
+ manufacturer = "Andor"
6
+ model = "iKon-M 934"
7
+ sensor_type = "CCD"
8
+ resolution = [1024, 1024] # (height, width) in pixels
9
+ pixel_size_um = 13.0
10
+ quantum_efficiency = 0.95 # peak QE (BV coating)
11
+ full_well_e = 130000.0
12
+ bit_depth = 16
13
+ gain_e_per_adu = 2.0
14
+ bias_offset_adu = 500.0
15
+ read_noise_e = 2.9 # at slow readout
16
+ dark_current_e_per_s = 0.00012 # at the reference temperature below
17
+ dark_current_ref_temp_c = -80.0
18
+ dark_current_doubling_temp_c = 6.3
19
+ dark_current_nonuniformity = 0.03
20
+ hot_pixel_fraction = 0.0002
21
+ hot_pixel_factor = 80.0
22
+ notes = "Deep-cooled (-80 C) back-illuminated CCD for low-light spectroscopy/imaging."
@@ -0,0 +1,22 @@
1
+ # Andor iXon Ultra 888 — back-illuminated EMCCD
2
+ name = "Andor iXon Ultra 888"
3
+ manufacturer = "Andor"
4
+ model = "iXon Ultra 888"
5
+ sensor_type = "EMCCD"
6
+ resolution = [1024, 1024]
7
+ pixel_size_um = 13.0
8
+ quantum_efficiency = 0.95
9
+ full_well_e = 80000.0
10
+ bit_depth = 16
11
+ gain_e_per_adu = 4.0 # system gain at the ADC
12
+ bias_offset_adu = 500.0
13
+ read_noise_e = 45.0 # large at the output amplifier; EM gain overcomes it
14
+ dark_current_e_per_s = 0.00025
15
+ dark_current_ref_temp_c = -80.0
16
+ dark_current_doubling_temp_c = 6.3
17
+ em_gain = 300.0
18
+ clock_induced_charge_e = 0.005 # spurious charge per pixel per frame
19
+ dark_current_nonuniformity = 0.04
20
+ hot_pixel_fraction = 0.0003
21
+ hot_pixel_factor = 60.0
22
+ notes = "EMCCD for single-photon-sensitive imaging; effective read noise <1 e- at high EM gain."
@@ -0,0 +1,18 @@
1
+ # A plain, well-behaved CCD for testing and teaching.
2
+ name = "Generic CCD"
3
+ sensor_type = "CCD"
4
+ resolution = [512, 512]
5
+ pixel_size_um = 15.0
6
+ quantum_efficiency = 0.85
7
+ full_well_e = 100000.0
8
+ bit_depth = 16
9
+ gain_e_per_adu = 1.5
10
+ bias_offset_adu = 400.0
11
+ read_noise_e = 5.0
12
+ dark_current_e_per_s = 0.1
13
+ dark_current_ref_temp_c = 20.0
14
+ dark_current_doubling_temp_c = 6.3
15
+ dark_current_nonuniformity = 0.05
16
+ hot_pixel_fraction = 0.001
17
+ hot_pixel_factor = 100.0
18
+ notes = "Idealised CCD with typical parameters; good default for examples."
@@ -0,0 +1,18 @@
1
+ # A plain, well-behaved CMOS for testing and teaching.
2
+ name = "Generic CMOS"
3
+ sensor_type = "CMOS"
4
+ resolution = [1080, 1920]
5
+ pixel_size_um = 5.0
6
+ quantum_efficiency = 0.80
7
+ full_well_e = 15000.0
8
+ bit_depth = 12
9
+ gain_e_per_adu = 1.0
10
+ bias_offset_adu = 200.0
11
+ read_noise_e = 2.0
12
+ dark_current_e_per_s = 2.0
13
+ dark_current_ref_temp_c = 20.0
14
+ dark_current_doubling_temp_c = 6.0
15
+ dark_current_nonuniformity = 0.04
16
+ hot_pixel_fraction = 0.002
17
+ hot_pixel_factor = 150.0
18
+ notes = "Idealised uncooled CMOS; higher dark current and lower full well than the CCD."
@@ -0,0 +1,20 @@
1
+ # A plain electron-avalanche photodiode (eAPD) array for testing and teaching.
2
+ name = "Generic eAPD"
3
+ sensor_type = "EAPD"
4
+ resolution = [256, 256]
5
+ pixel_size_um = 18.0
6
+ quantum_efficiency = 0.85
7
+ full_well_e = 80000.0
8
+ bit_depth = 16
9
+ gain_e_per_adu = 2.0
10
+ bias_offset_adu = 800.0
11
+ read_noise_e = 40.0 # amplifier read noise before avalanche gain
12
+ em_gain = 20.0 # avalanche gain
13
+ excess_noise_factor = 1.25
14
+ dark_current_e_per_s = 2.0
15
+ dark_current_ref_temp_c = -190.0
16
+ dark_current_doubling_temp_c = 8.0
17
+ dark_current_nonuniformity = 0.04
18
+ hot_pixel_fraction = 0.0005
19
+ hot_pixel_factor = 50.0
20
+ notes = "Idealised eAPD for demonstrating avalanche gain with a low excess noise factor."
@@ -0,0 +1,20 @@
1
+ # A plain EMCCD for testing and teaching.
2
+ name = "Generic EMCCD"
3
+ sensor_type = "EMCCD"
4
+ resolution = [512, 512]
5
+ pixel_size_um = 16.0
6
+ quantum_efficiency = 0.90
7
+ full_well_e = 100000.0
8
+ bit_depth = 16
9
+ gain_e_per_adu = 5.0
10
+ bias_offset_adu = 500.0
11
+ read_noise_e = 50.0
12
+ dark_current_e_per_s = 0.001
13
+ dark_current_ref_temp_c = -70.0
14
+ dark_current_doubling_temp_c = 6.3
15
+ em_gain = 200.0
16
+ clock_induced_charge_e = 0.01
17
+ dark_current_nonuniformity = 0.05
18
+ hot_pixel_fraction = 0.001
19
+ hot_pixel_factor = 80.0
20
+ notes = "Idealised EMCCD for demonstrating EM gain and clock-induced charge."
@@ -0,0 +1,21 @@
1
+ # A plain scientific CMOS (sCMOS) for testing and teaching.
2
+ name = "Generic sCMOS"
3
+ sensor_type = "SCMOS"
4
+ resolution = [2048, 2048]
5
+ pixel_size_um = 6.5
6
+ quantum_efficiency = 0.82
7
+ full_well_e = 30000.0
8
+ bit_depth = 16
9
+ gain_e_per_adu = 0.5
10
+ bias_offset_adu = 100.0
11
+ read_noise_e = 1.6 # median read noise
12
+ read_noise_nonuniformity = 0.3 # per-pixel spread
13
+ dark_current_e_per_s = 0.5
14
+ dark_current_ref_temp_c = -10.0
15
+ dark_current_doubling_temp_c = 6.0
16
+ prnu = 0.01
17
+ nonlinearity = 0.01
18
+ dark_current_nonuniformity = 0.03
19
+ hot_pixel_fraction = 0.001
20
+ hot_pixel_factor = 130.0
21
+ notes = "Idealised sCMOS demonstrating per-pixel read noise and mild nonlinearity."
@@ -0,0 +1,25 @@
1
+ # Hamamatsu ORCA-Fusion BT — back-thinned scientific CMOS (sCMOS).
2
+ # Representative parameters; sCMOS read noise varies pixel-to-pixel, captured here
3
+ # by read_noise_nonuniformity rather than a single RMS.
4
+ name = "Hamamatsu ORCA-Fusion BT"
5
+ manufacturer = "Hamamatsu"
6
+ model = "ORCA-Fusion BT (C15440)"
7
+ sensor_type = "SCMOS"
8
+ resolution = [2304, 2304]
9
+ pixel_size_um = 6.5
10
+ quantum_efficiency = 0.95
11
+ full_well_e = 18000.0
12
+ bit_depth = 16
13
+ gain_e_per_adu = 0.3
14
+ bias_offset_adu = 100.0
15
+ read_noise_e = 1.4 # median; see spread below
16
+ read_noise_nonuniformity = 0.35 # per-pixel read-noise spread (sCMOS)
17
+ dark_current_e_per_s = 0.2
18
+ dark_current_ref_temp_c = -10.0
19
+ dark_current_doubling_temp_c = 6.0
20
+ prnu = 0.01
21
+ nonlinearity = 0.01
22
+ dark_current_nonuniformity = 0.02
23
+ hot_pixel_fraction = 0.0005
24
+ hot_pixel_factor = 120.0
25
+ notes = "Back-thinned sCMOS; very high QE and low median read noise with a per-pixel spread."
@@ -0,0 +1,32 @@
1
+ # Leonardo SAPHIRA — HgCdTe electron-avalanche photodiode (eAPD) IR array.
2
+ # Widely used as an adaptive-optics wavefront-sensor and fringe-tracker detector.
3
+ # Values are representative; the avalanche gain is user-tunable via the bias.
4
+ name = "Leonardo SAPHIRA"
5
+ manufacturer = "Leonardo"
6
+ model = "SAPHIRA (Mark 13/14)"
7
+ sensor_type = "EAPD"
8
+ resolution = [256, 320] # (height, width)
9
+ pixel_size_um = 24.0
10
+ quantum_efficiency = 0.90 # HgCdTe, broad near-IR response
11
+ full_well_e = 100000.0
12
+ bit_depth = 16
13
+ gain_e_per_adu = 2.5 # system gain at the ADC
14
+ bias_offset_adu = 1000.0
15
+ read_noise_e = 45.0 # CDS read noise at the amplifier (pre-avalanche)
16
+ em_gain = 50.0 # avalanche gain M; effective read noise ~ 45/M ~ 1 e-
17
+ excess_noise_factor = 1.3 # eAPDs are far quieter than EMCCDs (sqrt(2))
18
+ dark_current_e_per_s = 5.0 # incl. dark-current avalanche / glow, cooled (~80 K)
19
+ dark_current_ref_temp_c = -193.0
20
+ dark_current_doubling_temp_c = 8.0
21
+ clock_induced_charge_e = 0.0
22
+ dark_current_nonuniformity = 0.05
23
+ hot_pixel_fraction = 0.0005
24
+ hot_pixel_factor = 50.0
25
+ notes = "Sub-electron effective read noise at high avalanche gain; near-unity excess noise."
26
+
27
+ # Wavelength-resolved quantum efficiency (HgCdTe, ~2.5 um cutoff). Optional; only
28
+ # used in spectral mode (Camera.observe with a band that has a spectral response).
29
+ # Representative shape --- supply a measured curve for quantitative IR work.
30
+ [qe_curve]
31
+ wavelength_nm = [800.0, 1000.0, 1500.0, 2000.0, 2400.0, 2500.0]
32
+ qe = [0.45, 0.85, 0.90, 0.90, 0.80, 0.30]
@@ -0,0 +1,20 @@
1
+ # ZWO ASI2600MM Pro — Sony IMX571 back-illuminated CMOS
2
+ name = "ZWO ASI2600MM Pro"
3
+ manufacturer = "ZWO"
4
+ model = "ASI2600MM Pro (IMX571)"
5
+ sensor_type = "CMOS"
6
+ resolution = [4176, 6248]
7
+ pixel_size_um = 3.76
8
+ quantum_efficiency = 0.91
9
+ full_well_e = 50000.0
10
+ bit_depth = 16
11
+ gain_e_per_adu = 0.25 # unity-gain regime; low-noise mode
12
+ bias_offset_adu = 500.0
13
+ read_noise_e = 1.5 # at high conversion gain
14
+ dark_current_e_per_s = 0.0022
15
+ dark_current_ref_temp_c = -10.0
16
+ dark_current_doubling_temp_c = 6.0
17
+ dark_current_nonuniformity = 0.02
18
+ hot_pixel_fraction = 0.0005
19
+ hot_pixel_factor = 120.0
20
+ notes = "Popular cooled astrophotography/scientific CMOS; very low read noise."
getframes/py.typed ADDED
File without changes
@@ -0,0 +1,51 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """The scene/optics layer: turn astrophysical inputs into a photon-rate map.
3
+
4
+ Build a :class:`Scene` from sources, a :class:`PSF`, and a :class:`Telescope`,
5
+ then either call :meth:`Scene.photon_rate_map` yourself or hand the scene to
6
+ :meth:`getframes.Camera.observe` to get a realistic frame.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from .optics import RadialDistortion, Telescope, Vignetting
12
+ from .photometry import Bandpass, Extinction
13
+ from .psf import PSF, AiryPSF, ArrayPSF, EllipticalGaussianPSF, GaussianPSF, MoffatPSF
14
+ from .scene import Scene
15
+ from .sources import (
16
+ Catalog,
17
+ CatalogEntry,
18
+ ExtendedSource,
19
+ LightCurve,
20
+ PointSource,
21
+ Sky,
22
+ Source,
23
+ UniformIllumination,
24
+ )
25
+ from .thermal import Thermal
26
+ from .wcs import WCSInfo
27
+
28
+ __all__ = [
29
+ "PSF",
30
+ "AiryPSF",
31
+ "ArrayPSF",
32
+ "Bandpass",
33
+ "Catalog",
34
+ "CatalogEntry",
35
+ "EllipticalGaussianPSF",
36
+ "ExtendedSource",
37
+ "Extinction",
38
+ "GaussianPSF",
39
+ "LightCurve",
40
+ "MoffatPSF",
41
+ "PointSource",
42
+ "RadialDistortion",
43
+ "Scene",
44
+ "Sky",
45
+ "Source",
46
+ "Telescope",
47
+ "Thermal",
48
+ "UniformIllumination",
49
+ "Vignetting",
50
+ "WCSInfo",
51
+ ]