pyrtc.calibration

Versioned calibration files and the migration of pyrtc 1.x calibrations.

pyrtc 2.0 changed two conventions that saved calibrations depend on:

  • Image streams are (height, width), indexed [y, x] with x along the columns (aocore CONVENTIONS 1.1, #162). pyrtc 1.x declared them (width, height), and some camera adapters (GenICam, Micro-Manager) transposed each frame into that shape. Slope x/y now follow the camera’s columns/rows.

  • Shack-Hartmann sub-aperture pixel k sits at k - (n - 1) / 2 (CONVENTIONS 1.2, #163), not k - n // 2. Raw slopes of even-sized sub-apertures moved by +0.5 px; residual slopes did not.

Calibration files written since 2.0 are .npz archives holding the array (data) and a JSON record (pyrtc_calibration) with the format version and the kind of calibration. They keep whatever file name the config gives, and np.load opens them (it returns an NpzFile; the array is ["data"]). load_calibration() reads both kinds of file.

A file without the record is a legacy (pyrtc 1.x) file. Components refuse legacy files unless their config section sets legacy_calibration, which says how the file was made:

"yx"

The camera adapter published frames unchanged (XIMEA, Spinnaker, OOPAO, HCIPy, SPECULA, the synthetic simulators). Arrays load as they are; SHWFS reference slopes of even sub-apertures move by +0.5 px (#163).

"xy"

The adapter transposed frames into (width, height) streams (GenICam, Micro-Manager, or an adapter of your own that applied frame.T). Images are transposed, slope maps and valid sub-aperture masks swap their x/y halves and transpose each, and SHWFS reference slopes also move by +0.5 px. An interaction matrix needs the 1.x valid sub-aperture mask to reorder its rows, so it is converted offline with pyrtc-migrate-calibration (migrate_calibration_file()).

"as_is"

The file already follows the 2.0 conventions (made by hand or by another tool); it loads unchanged.

Every conversion here is exact. The one case that is not, a WCoG reference taken without a reference image (its Gaussian weight moved by half a pixel with #163), is refused. See the “Migrating to pyrtc 2.0” docs page.

Module Attributes

CALIBRATION_FORMAT

Current calibration format: [y, x] image arrays, pixel-centred SHWFS coordinates.

CALIBRATION_KINDS

What each kind of calibration holds, and how to measure it again.

Functions

image_from_legacy(image, legacy_frame)

Convert a 1.x image-shaped array (dark, model PSF, reference image).

interaction_matrix_from_legacy(...[, ...])

Convert a 1.x interaction matrix (signal_size, num_modes).

legacy_calibration_message(path, kind[, reason])

Explain why a legacy file was refused and how to convert or re-measure it.

load_calibration(filename[, kind])

Read a calibration file, versioned (2.0+) or legacy (a plain .npy).

load_component_calibration(filename, kind, ...)

Load a calibration for a component, converting or refusing a legacy file.

migrate_calibration_file(source, ...[, ...])

Convert a 1.x calibration file and save it in the 2.0 format.

normalize_legacy_calibration(value)

Validate a legacy_calibration config value (None or empty: refuse).

read_calibration_array(filename, kind)

Return the array of a 2.0 calibration file; refuse a legacy one.

save_calibration(filename, data, kind, ...)

Write data as a versioned calibration file and return its path.

shwfs_ref_slopes_from_legacy(ref_slopes, ...)

Convert 1.x SHWFS reference slopes ((2N, N) in pixels).

signal_permutation_from_legacy(...[, ...])

Return (order, new_valid_sub_aps) for 1.x slope vectors.

slope_map_from_legacy(slope_map, legacy_frame)

Convert a 1.x 2-D slope map or valid sub-aperture mask (the signal_2d layout).

Classes

Calibration(data, metadata, path)

A loaded calibration array and its record (None for a legacy file).

Exceptions

CalibrationError

A calibration file that pyrtc cannot use as it is.

LegacyCalibrationError

A pyrtc 1.x calibration file that was not (or cannot be) converted.