spindoctor.obs

class Obs(*, config: Config | None = None, **kwargs: Any)[source]

Bases: ABC, NavBase

Represents an observation in the navigation system.

This abstract base class provides common functionality for all observation types, including configuration and logging capabilities.

class ObsSnapshot(snapshot: Snapshot, *, extfov_margin_vu: int | tuple[int, int] | None = None, config: Config | None = None, **kwargs: Any)[source]

Bases: Obs, Snapshot

Provides cached Backplane and Meshgrid operations for snapshot observations.

This class extends both Obs and Snapshot to provide navigation-specific functionality for snapshot observations, including FOV management and backplane caching.

body_distance(body: str) float[source]

Computes the distance from the spacecraft to the specified celestial body.

Parameters:

body – Name of the celestial body.

Returns:

Distance in kilometers from the spacecraft to the specified body.

property bp: Backplane

Returns a Backplane for the entire original FOV, creating it if needed.

property center_bp: Backplane

Create a Backplane with only a single point in the center.

clip_extfov(u: int, v: int) tuple[int, int][source]

Clips coordinates to ensure they are within the extended FOV boundaries.

Parameters:
  • u – U coordinate to clip

  • v – V coordinate to clip

Returns:

A tuple of (u, v) coordinates clipped to the extended FOV boundaries.

clip_fov(u: int, v: int) tuple[int, int][source]

Clips coordinates to ensure they are within the original FOV boundaries.

Parameters:
  • u – U coordinate to clip

  • v – V coordinate to clip

Returns:

A tuple of (u, v) coordinates clipped to the FOV boundaries.

clip_rect_extfov(u_min: int, u_max: int, v_min: int, v_max: int) tuple[int, int, int, int][source]

Clip a rectangle to the extended FOV bounds.

Returns:

(u0, u1, v0, v1) clipped to [extfov_u_min..extfov_u_max], [extfov_v_min..extfov_v_max]

clip_rect_fov(u_min: int, u_max: int, v_min: int, v_max: int) tuple[int, int, int, int][source]

Clip a rectangle to the original FOV bounds.

Returns:

(u0, u1, v0, v1) clipped to [fov_u_min..fov_u_max], [fov_v_min..fov_v_max]

property closest_planet: str | None
property corner_bp: Backplane

Create a Backplane with points only in the four corners of the original FOV.

property data_shape_u: int
property data_shape_uv: tuple[int, int]
property data_shape_v: int
property data_shape_vu: tuple[int, int]
property ext_bp: Backplane

Create a Backplane for the entire extended FOV.

When the extended-FOV margin is (0, 0) the extended Backplane is identical to bp, so this returns the same Backplane object rather than a copy. Callers must not mutate the result in place assuming the extended and non-extended caches are independent.

property ext_corner_bp: Backplane

Create a Backplane with points only in the four corners of the extended FOV.

As with ext_bp, when the extended-FOV margin is (0, 0) this returns the same object as corner_bp; do not mutate it assuming the extended and non-extended caches are independent.

property extdata: NDArray[floating[Any]]
property extdata_shape_uv: tuple[int, int]
property extdata_shape_vu: tuple[int, int]
extfov_data_sensor_mask() NDArray[bool][source]

Boolean mask over extdata that is True where real sensor data lives.

extdata wraps data in a zero-padded margin so that correlation can search offsets outside the original field of view. The returned mask is True inside the original-FOV rectangle and False in the zero-padded margin.

Returns:

Boolean array with the same shape as extdata; True for the inner extfov_margin_v : extfov_margin_v + data_shape_v x extfov_margin_u : extfov_margin_u + data_shape_u region.

property extfov_margin_u: int
property extfov_margin_v: int
property extfov_margin_vu: tuple[int, int]
property extfov_u_max: int
property extfov_u_min: int
property extfov_v_max: int
property extfov_v_min: int
property extfov_vu_max: tuple[int, int]
property extfov_vu_min: tuple[int, int]
extract_offset_array(array: NDArray[NPType], offset: tuple[float, float] | tuple[int, int] | None) NDArray[NPType][source]

Extracts a full-size array from the given extended FOV array.

Parameters:
  • array – Array to extract the subimage from. This must be the same shape as the extended FOV.

  • offset – Offset (dv,du) to extract the subarray at. An offset of (0,0) means to extract the center of the normal FOV. A positive offset means to extract in the negative direction of v and u.

Returns:

The extracted subimage, shaped like the original (unpadded) FOV. When the offset exceeds the extfov margin in either axis, the requested slice is partly outside the extfov; the in-bounds portion is copied from array and the out-of-bounds portion is zero-filled (or False for boolean input). This is the right semantic for overlay / model arrays — pixels outside the extfov simply have no predicted content there.

property fov_u_max: int
property fov_u_min: int
property fov_v_max: int
property fov_v_min: int
property fov_vu_max: tuple[int, int]
property fov_vu_min: tuple[int, int]
inventory_body_in_extfov(inv: dict[str, Any]) bool[source]

Returns True if an inventory box overlaps the extended FOV.

inventory_body_in_fov(inv: dict[str, Any]) bool[source]

Returns True if an inventory box overlaps the original FOV.

make_extfov_false() NDArray[bool][source]

Creates a boolean array of False values matching the extended FOV dimensions.

Returns:

A boolean array of False values with the same shape as the extended FOV.

make_extfov_zeros(dtype: DTypeLike = <class 'numpy.float64'>) NDArray[floating[Any]][source]

Creates a zero-filled array matching the extended FOV dimensions.

Parameters:

dtype – Data type for the array elements.

Returns:

A zero-filled array with the same shape as the extended FOV.

make_fov_zeros(dtype: DTypeLike = <class 'numpy.float64'>) NDArray[floating[Any]][source]

Creates a zero-filled array matching the original FOV dimensions.

Parameters:

dtype – Data type for the array elements.

Returns:

A zero-filled array with the same shape as the original data.

ra_dec_limits(apparent: bool = True) tuple[float, float, float, float][source]

Finds the right ascension and declination limits of the observation using the standard FOV.

Parameters:

apparent – Whether to compensate for aberration and light travel time.

Returns:

A tuple containing (ra_min, ra_max, dec_min, dec_max) in radians.

ra_dec_limits_ext(apparent: bool = True) tuple[float, float, float, float][source]

Finds the right ascension and declination limits of the observation using the extended FOV.

Parameters:

apparent – Whether to compensate for aberration and light travel time.

Returns:

A tuple containing (ra_min, ra_max, dec_min, dec_max) in radians.

reset_all() None[source]

Resets all cached Backplanes and Meshgrids to their initial state.

Clears all cached computations, forcing them to be regenerated on next access.

sun_body_distance(body: str) float[source]

Computes the distance from the Sun to the specified celestial body in kilometers.

Parameters:

body – Name of the celestial body.

Returns:

Distance in kilometers from the Sun to the specified body.

unpad_array_to_extfov(array: NDArray[NPType]) NDArray[NPType][source]

Crop an array down to the extended-FOV (extdata) shape.

Slices array to extdata_shape_vu by keeping the top-left region; any extra rows/columns are dropped. This is most useful for trimming the result of np.unpackbits, which rounds the bit-unpacked length up to a multiple of 8 and so can be larger than the extended FOV.

Parameters:

array – Array at least as large as extdata_shape_vu in both axes; only its top-left extdata_shape_vu region is kept.

Returns:

The array cropped to extdata_shape_vu.

class ObsSnapshotInst(snapshot: Snapshot, **kwargs: Any)[source]

Bases: ObsSnapshot, ObsInst

Mix-in of ObsSnapshot and ObsInst.

class ObsInst(**kwargs: Any)[source]

Bases: ABC

Mix-in class for instrument models representing spacecraft cameras.

This class provides default functionality for methods related to instruments and abstract methods for instrument-specific functionality.

abstract property camera: str

The camera that took this observation.

Instruments with more than one camera distinguish them here (Cassini ISS and Voyager ISS return 'NAC' or 'WAC'); single-camera instruments return their one camera’s name. Pointing error is a property of the camera, not of the instrument, so statistics are grouped by this value.

Returns:

The camera name.

abstractmethod static from_file(path: str | Path | FCPath, *, config: Config | None = None, extfov_margin_vu: tuple[int, int] | None = None, **kwargs: Any) Obs[source]

Creates an instrument instance from an image file.

Parameters:
  • path – Path to the image file.

  • config – Configuration object to use. If None, uses DEFAULT_CONFIG.

  • extfov_margin_vu – Optional tuple specifying the extended field of view margins in (vertical, horizontal) pixels.

  • **kwargs – Additional keyword arguments to pass to the instrument constructor.

Returns:

An Obs object containing the image data and metadata.

abstractmethod get_public_metadata() dict[str, Any][source]

Returns the public metadata for this instrument.

property inst_config: dict[str, Any] | None

Returns the instrument configuration.

abstractmethod star_max_usable_vmag() float[source]

Returns the maximum usable magnitude for stars in this observation.

Returns:

The maximum usable magnitude for stars in this observation.

abstractmethod star_min_usable_vmag() float[source]

Returns the minimum usable magnitude for stars in this observation.

Returns:

The minimum usable magnitude for stars in this observation.

star_psf() PSF[source]

Returns the point spread function (PSF) model appropriate for stars observed by this instrument.

This generic implementation uses the “star_psf_sigma” configuration value and creates a Gaussian PSF with that sigma.

Returns:

A PSF model appropriate for stars observed by this instrument.

star_psf_size(star: Star) tuple[int, int][source]

Returns the size of the point spread function (PSF) to use for a star.

This generic implementation uses the “star_psf_sizes” configuration value and returns the appropriate value for the star’s magnitude.

Parameters:

star – The star to get the PSF size for.

Returns:

A tuple of the PSF size (v, u) in pixels.

class ObsCassiniISS(snapshot: Snapshot, **kwargs: Any)[source]

Bases: ObsSnapshotInst

Implements an observation of a Cassini ISS image.

This class provides specialized functionality for accessing and analyzing Cassini ISS image data.

property camera: str

The camera that took this observation.

Returns:

'NAC' or 'WAC'.

Return type:

The oops detector name

static from_file(path: str | Path | FCPath, *, config: Config | None = None, extfov_margin_vu: tuple[int, int] | None = None, **kwargs: Any) ObsCassiniISS[source]

Creates an ObsCassiniISS from a Cassini ISS image file.

Parameters:
  • path – Path to the Cassini ISS image file.

  • config – Configuration object to use. If None, uses the default configuration.

  • extfov_margin_vu – Optional tuple that overrides the extended field of view margins found in the config.

  • **kwargs

    Additional keyword arguments:

    • fast_distortion: Whether to use a fast distortion model.

    • return_all_planets: Whether to return all planets.

Returns:

An ObsCassiniISS object containing the image data and metadata.

get_public_metadata() dict[str, Any][source]

Returns the public metadata for Cassini ISS.

Returns:

A dictionary containing the public metadata for Cassini ISS.

star_max_usable_vmag() float[source]

Returns the maximum usable magnitude for stars in this observation.

Returns:

The maximum usable magnitude for stars in this observation.

star_min_usable_vmag() float[source]

Returns the minimum usable magnitude for stars in this observation.

Returns:

The minimum usable magnitude for stars in this observation.

class ObsVoyagerISS(snapshot: Snapshot, **kwargs: Any)[source]

Bases: ObsSnapshotInst

Implements an observation of a Voyager ISS image.

This class provides specialized functionality for accessing and analyzing Voyager ISS image data.

property camera: str

The camera that took this observation.

Returns:

'NAC' or 'WAC'.

Return type:

The oops detector name

static from_file(path: str | Path | FCPath, *, config: Config | None = None, extfov_margin_vu: tuple[int, int] | None = None, **_kwargs: Any) ObsVoyagerISS[source]

Creates an ObsVoyagerISS from a Voyager ISS image file.

Parameters:
  • path – Path to the Voyager ISS image file.

  • config – Configuration object to use. If None, uses the default configuration.

  • extfov_margin_vu – Optional tuple that overrides the extended field of view margins found in the config.

  • **_kwargs – Additional keyword arguments (none for this instrument).

Returns:

An ObsVoyagerISS object containing the image data and metadata.

get_public_metadata() dict[str, Any][source]

Returns the public metadata for Voyager ISS.

Returns:

A dictionary containing the public metadata for Voyager ISS.

star_max_usable_vmag() float[source]

Returns the maximum usable magnitude for stars in this observation.

The limiting magnitude follows the Cassini Pogson-ratio form,

star_max_usable_vmag(texp) = anchor + log(texp) / log(2.512)

where anchor is the limiting magnitude at a 1 s exposure (each 2.512x increase in exposure buys +1 mag of depth).

The anchor is scaled from the Cassini NAC anchor (10.5 mag at 1 s, aperture D = 0.19 m) by collecting-area, with a detector-sensitivity term for the Voyager vidicon (roughly 2 mag less sensitive than a CCD). These are nominal optics values; the terms are approximate and pending calibration against real Voyager star fields.

anchor = 10.5 + 5*log10(D / 0.19) + detector_term

Per camera (apertures from the Voyager ISS optics; vidicon detector):

NAC: 10.5 + 5*log10(0.176/0.19) - 2.0 (vidicon) ~= 8.3 WAC: 10.5 + 5*log10(0.057/0.19) - 2.0 (vidicon) ~= 5.9

Returns:

The maximum usable magnitude for stars in this observation.

star_min_usable_vmag() float[source]

Returns the minimum usable magnitude for stars in this observation.

Mirrors the Cassini ISS reference implementation, which imposes no bright-end cutoff (saturation of bright stars is handled elsewhere).

Returns:

The minimum usable magnitude for stars in this observation.

class ObsGalileoSSI(snapshot: Snapshot, **kwargs: Any)[source]

Bases: ObsSnapshotInst

Implements an observation of a Galileo SSI image.

This class provides specialized functionality for accessing and analyzing Galileo SSI image data.

property camera: str

The camera that took this observation.

Returns:

Always 'SSI'; Galileo carries a single camera.

static from_file(path: str | Path | FCPath, *, config: Config | None = None, extfov_margin_vu: tuple[int, int] | None = None, **_kwargs: Any) ObsGalileoSSI[source]

Creates an ObsGalileoSSI from a Galileo SSI image file.

Parameters:
  • path – Path to the Galileo SSI image file.

  • config – Configuration object to use. If None, uses the default configuration.

  • extfov_margin_vu – Optional tuple that overrides the extended field of view margins found in the config.

  • **_kwargs – Additional keyword arguments (none for this instrument).

Returns:

An ObsGalileoSSI object containing the image data and metadata.

get_public_metadata() dict[str, Any][source]

Returns the public metadata for Galileo SSI.

Returns:

A dictionary containing the public metadata for Galileo SSI.

star_max_usable_vmag() float[source]

Returns the maximum usable magnitude for stars in this observation.

The limiting magnitude follows the Cassini Pogson-ratio form,

star_max_usable_vmag(texp) = anchor + log(texp) / log(2.512)

where anchor is the limiting magnitude at a 1 s exposure (each 2.512x increase in exposure buys +1 mag of depth).

The anchor is scaled from the Cassini NAC anchor (10.5 mag at 1 s, aperture D = 0.19 m) by collecting-area. Galileo SSI uses a CCD, so no detector-sensitivity penalty is applied. These are nominal optics values; the term is approximate and pending calibration against real Galileo star fields.

anchor = 10.5 + 5*log10(0.176/0.19) (CCD) ~= 10.3

Returns:

The maximum usable magnitude for stars in this observation.

star_min_usable_vmag() float[source]

Returns the minimum usable magnitude for stars in this observation.

Mirrors the Cassini ISS reference implementation, which imposes no bright-end cutoff (saturation of bright stars is handled elsewhere).

Returns:

The minimum usable magnitude for stars in this observation.

class ObsNewHorizonsLORRI(snapshot: Snapshot, **kwargs: Any)[source]

Bases: ObsSnapshotInst

Implements an observation of a New Horizons LORRI image.

This class provides specialized functionality for accessing and analyzing New Horizons LORRI image data.

property camera: str

The camera that took this observation.

Returns:

Always 'LORRI'; New Horizons LORRI is a single camera.

static from_file(path: str | Path | FCPath, *, config: Config | None = None, extfov_margin_vu: tuple[int, int] | None = None, **_kwargs: Any) ObsNewHorizonsLORRI[source]

Creates an ObsNewHorizonsLORRI from a New Horizons LORRI image file.

Parameters:
  • path – Path to the New Horizons LORRI image file.

  • config – Configuration object to use. If None, uses the default configuration.

  • extfov_margin_vu – Optional tuple that overrides the extended field of view margins found in the config.

  • **_kwargs – Additional keyword arguments (none for this instrument).

Returns:

An ObsNewHorizonsLORRI object containing the image data and metadata.

get_public_metadata() dict[str, Any][source]

Returns the public metadata for New Horizons LORRI.

Returns:

A dictionary containing the public metadata for New Horizons LORRI.

star_max_usable_vmag() float[source]

Returns the maximum usable magnitude for stars in this observation.

The limiting magnitude follows the Cassini Pogson-ratio form,

star_max_usable_vmag(texp) = anchor + log(texp) / log(2.512)

where anchor is the limiting magnitude at a 1 s exposure (each 2.512x increase in exposure buys +1 mag of depth).

The anchor is scaled from the Cassini NAC anchor (10.5 mag at 1 s, aperture D = 0.19 m) by collecting-area. New Horizons LORRI uses a CCD (no detector-sensitivity penalty) and is panchromatic with no filter, so a bandpass term of +1.0 mag is added to account for the wider passband collecting more flux. These are nominal optics values; the terms are approximate and pending calibration against real LORRI star fields.

anchor = 10.5 + 5*log10(0.208/0.19) (CCD) + 1.0 (panchromatic) ~= 11.7

Returns:

The maximum usable magnitude for stars in this observation.

star_min_usable_vmag() float[source]

Returns the minimum usable magnitude for stars in this observation.

Mirrors the Cassini ISS reference implementation, which imposes no bright-end cutoff (saturation of bright stars is handled elsewhere).

Returns:

The minimum usable magnitude for stars in this observation.

Observation snapshot backed by a simulated-image scene.

ObsSim wraps a rendered sim scene as an oops Snapshot with a flat FOV and dummy geometry, so the standard navigation pipeline runs on it exactly as on a real frame. The rendered image and the full scene (truth included) stay on the snapshot for renderer-side consumers; the navigator-side models see only the filtered idealized view exposed as obs.nav_params (the information boundary – see spindoctor.sim.scene.build_nav_params()).

class ObsSim(snapshot: Snapshot, **kwargs: Any)[source]

Bases: ObsSnapshotInst

Observation backed by a description of simulated bodies and stars.

property camera: str

The camera that took this observation.

Returns:

Always 'SIM'; a simulated scene has one synthetic camera.

static from_file(path: str | Path | FCPath, *, config: Config | None = None, extfov_margin_vu: tuple[int, int] | None = None, **kwargs: Any) ObsSim[source]

Creates an ObsSim from a YAML scene file.

Parameters:
  • path – Path to the YAML scene file.

  • config – Navigation configuration. If None, uses defaults.

  • extfov_margin_vu – Optional extended FOV margins (v,u) to add around the image.

  • **kwargs – Additional keyword arguments. sim_params: Flat sim-params mapping. If present, this overrides the scene file.

Returns:

the rendered image as data, the full scene and renderer truth metadata on the snapshot, and the filtered idealized view as nav_params.

Return type:

The ObsSim wrapping the rendered scene

get_public_metadata() dict[str, Any][source]

Returns the public metadata for this instrument.

star_max_usable_vmag() float[source]

Returns the maximum usable magnitude for stars in this observation.

Derived from the emulated instrument’s PUBLISHED detector model, never from the scene’s truth-side noise block: the navigator may know only what a real pipeline could know about the camera. The renderer flux-normalizes a star (its total signal is star_flux_dn_per_s_vmag0 * 10**(-0.4 * vmag) * exposure, see spindoctor.sim.forward); a Gaussian core of the published star_psf_sigma then puts a fraction 1 / (2*pi*sigma**2) of that total in the peak pixel. The limiting magnitude is where that peak falls to twice the effective per-pixel noise sigma – the matched-filter detection boundary. The published DN zero point is the camera’s electron zero point over its standard gain state, so a real navigator could know it; the scene’s truth-side noise block is deliberately not consulted, so a scene that plants noise different from the published values produces an honestly-wrong detection limit, which is desired model error, not a defect. Keeping this physical matters beyond the faint-star gate: the star NavModel synthesises each STAR feature’s predicted SNR (and from it the CRLB position covariance and reliability score) from how far the star sits above this limit, so an arbitrarily permissive placeholder inflates every simulated star’s SNR by tens of orders of magnitude and collapses its covariance to zero.

The exposure the flux formula scales by is the scene’s idealized exposure_sec, read from the navigator-visible nav_params view: exposure is commanded, published information a real pipeline always has, and the renderer multiplies every star’s deposited flux by it, so the detection limit must move by 2.5 * log10(exposure) alongside the flux or a long exposure’s faint stars are gated out (and a short exposure’s noise floor is overstated). The dummy Snapshot’s texp deliberately stays at the 1-second reference: texp feeds the observation’s timing (midtime = tstart + texp / 2 anchors every time-dependent oops computation and the reported exposure metadata), and repurposing it would move the sim epoch as a side effect of a photometric knob, so the limit reads the exposure directly instead.

Returns:

The maximum usable magnitude for stars in this observation. For calibrated-unit sim instruments the published block carries no DN zero point to anchor a matched-filter limit, so the navigator uses a generous constant.

star_min_usable_vmag() float[source]

Returns the minimum usable magnitude for stars in this observation.

Returns:

The minimum usable magnitude for stars in this observation.