Skip to content

Add optika.distortion.PolynomialDistortionModel which can interpolate between object and sensor coordinates.#154

Merged
roytsmart merged 8 commits into
mainfrom
feature/polynomial-distortion
May 30, 2026
Merged

Add optika.distortion.PolynomialDistortionModel which can interpolate between object and sensor coordinates.#154
roytsmart merged 8 commits into
mainfrom
feature/polynomial-distortion

Conversation

@roytsmart
Copy link
Copy Markdown
Collaborator

Summary

Adds the optika.distortion subpackage for mapping scene coordinates (wavelength + field position) to sensor coordinates and back.

  • AbstractDistortionModel — defines the distort/undistort interface. Distortion carries wavelength alongside position (the scene→sensor mapping generally depends on wavelength, e.g. spectrograph dispersion), so the two methods are inverses only up to model accuracy.
  • AbstractInterpolatedDistortionModel — adds the calibration-point interface (coordinates_scene, coordinates_sensor, axis_wavelength, axis_field).
  • PolynomialDistortionModel — fits separate forward and inverse polynomials via na.PolynomialFitFunctionArray, using a mean-centered reference (center=inputs.mean(...)) for numerical conditioning. The underlying fits are exposed as the public fit/fit_inverse cached properties for introspection (coefficients, rms, etc.).

Registers the subpackage in optika/__init__.py.

Notes

This factors the distortion concept into a reusable object. The inline polynomial-distortion logic in systems/_interpolated.py (distortion/distortion_inverse) is a natural follow-up to migrate onto this abstraction.

Testing

  • pytest optika/distortion/_distortion_test.py — 22 passed (round-trip, type, and fit-introspection tests across degree ∈ {1, 2}).
  • black --check and ruff check clean.

🤖 Generated with Claude Code

roytsmart and others added 2 commits May 30, 2026 09:09
Introduce the `optika.distortion` subpackage, which maps scene
coordinates (wavelength + field position) to sensor coordinates and
back:

- `AbstractDistortionModel` defines the `distort`/`undistort` interface.
- `AbstractInterpolatedDistortionModel` adds the calibration-point
  interface (`coordinates_scene`, `coordinates_sensor`, axes).
- `PolynomialDistortionModel` fits forward and inverse polynomials (with
  a mean-centered reference for conditioning) and exposes them as the
  public `fit`/`fit_inverse` cached properties.

Register the subpackage in `optika/__init__.py` and add round-trip tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The distortion model relies on named-arrays features (the polynomial fit
`center` field) that are only available in named-arrays 1.5+.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.29%. Comparing base (22a9629) to head (ccc1d2a).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #154      +/-   ##
==========================================
+ Coverage   99.27%   99.29%   +0.01%     
==========================================
  Files         108      111       +3     
  Lines        5391     5537     +146     
==========================================
+ Hits         5352     5498     +146     
  Misses         39       39              
Flag Coverage Δ
unittests 99.29% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Plot the magnitude of the forward-fit residual (calibration sensor
positions minus fit predictions) as a function of field angle using
`na.plt.pcolormesh`, with a separate subplot for each wavelength and a
shared colorbar. Update the class example to demonstrate it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@roytsmart roytsmart changed the title Add optika.distortion, a polynomial model of optical distortion Add optika.distortion.PolynomialDistortionModel which can interpolate between object and sensor coordinates. May 30, 2026
roytsmart and others added 5 commits May 30, 2026 13:47
Replace the if/else branch selecting the subplot count with
`na.shape(wavelength).get(axis_wavelength, 1)`, which the existing tests
fully exercise (the scalar-wavelength else-branch was never hit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use a non-interactive matplotlib backend in CI so plotting tests (e.g.
`PolynomialDistortionModel.plot_residual`) run headless, matching the
named-arrays workflow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the example sensor distortion quadratic in both field components,
increase the field sampling, and set the subplot aspect ratio to equal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`vmin`/`vmax` set the residual color limits (defaulting to zero and the
maximum residual). `figsize` overrides the figure size; when omitted it
is now derived automatically from the number of wavelength subplots and
the field-of-view aspect ratio (via `field.x.ptp() / field.y.ptp()`).
Extend the test to exercise the new arguments.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@roytsmart roytsmart merged commit 2a2fe34 into main May 30, 2026
12 checks passed
@roytsmart roytsmart deleted the feature/polynomial-distortion branch May 30, 2026 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant