aobasis
Modal basis sets for adaptive-optics deformable mirrors: KL, Zernike, Fourier, Hadamard, zonal and zonal-fast modes, for any actuator geometry.
Every generator takes your actuator positions and returns a modal-to-command matrix (M2C), an (n_actuators, n_modes) NumPy array whose column k is the DM command for mode k. It's ready for a reconstructor, a calibration sequence or a real-time controller such as pyRTC.
Installation
pip install aobasis # numpy + scipy only
pip install "aobasis[plot]" # + matplotlib, for .plot()
pip install "aobasis[fits]" # + astropy, for save_fits / load_fits
pip install "aobasis[tutorials]" # + matplotlib, astropy and Jupyter, for the tutorials
aobasis is pure Python (3.8–3.14) and is tested on Linux, x86-64 and aarch64.
GPU (optional). KLBasisGenerator(..., use_gpu=True) builds and diagonalizes the covariance with CuPy. Install the CuPy wheel for your CUDA version, e.g. pip install cupy-cuda12x, or conda install -c conda-forge cupy. Without CuPy it falls back to the CPU with a warning, and the modes are the same either way.
Quick start
import numpy as np
import aobasis
# 1. Actuator positions: (N, 2) in metres, centred, in your DM's actuator order
positions = aobasis.make_circular_actuator_grid(telescope_diameter=10.0, grid_size=20)
# 2. A generator and its physical parameters
kl = aobasis.KLBasisGenerator(positions, fried_parameter=0.16, outer_scale=30.0)
# 3. The M2C: (276, 50), piston-free
m2c = kl.generate(n_modes=50, ignore_piston=True)
# 4. Use, inspect, keep
coefficients = np.zeros(50); coefficients[3] = 1.0 # some of mode 3
commands = m2c @ coefficients # put modal coefficients on the DM
c2m = aobasis.command_to_mode_matrix(m2c) # and back
kl.plot(count=6) # needs aobasis[plot]
kl.save("kl_m2c.npz") # modes + parameters + options + eigenvalues
What's in it
Bases
| Generator | Modes | Typical use |
|---|---|---|
KLBasisGenerator |
Karhunen-Loève modes of Von Kármán (or Kolmogorov, outer_scale=np.inf) turbulence at the actuators, with eigenvalues |
closed-loop control; turbulence statistics and priors |
DMKLBasisGenerator |
KL modes of the DM surface from its influence functions (double diagonalization) | control with a real DM |
ZernikeBasisGenerator |
Noll-normalized Zernikes in Noll, OSA/ANSI or Fringe order; annular Zernikes with obscuration= |
aberration commands, optical testing, NCPA |
FourierBasisGenerator |
sines and cosines, aliased frequencies skipped | frequency response, spatial filtering |
HadamardBasisGenerator |
±1 patterns, Sylvester or Paley matrices (construction="smallest"), selection="balanced" |
low-noise interaction-matrix calibration |
ZonalBasisGenerator |
single-actuator pokes | simplest calibration |
ZonalFastBasisGenerator |
groups of pokes at least min_distance apart (optimal lattice colourings) |
calibration in a few frames |
Shaping a basis. These options are the same on every generator:
ignore_piston=Truemakes every mode exactly zero-mean;remove="tiptilt"(or any(n_actuators, k)array, e.g. waffle) keeps other modes out;orthonormalize=TrueGram-Schmidts the modes in order;normalize="rms" | "l2" | "peak" | "pv"sets the scale.
Unknown options raise TypeError.
Geometry.
make_circular_actuator_gridbuilds a square grid bygrid_sizeorpitch, with actuators on the rim or in cell centres.make_hexagonal_actuator_gridandmake_concentric_actuator_gridcover other layouts.- All three take a central obstruction and spider arms.
positions_from_maskreads a boolean DM map, and any(N, 2)array works too.
Influence functions. fit_to_influence_functions gives least-squares commands whose DM surface matches modes sampled on the pupil. gaussian_influence_functions and make_pupil_points build the inputs.
Using and keeping a basis.
command_to_mode_matrixandfit_coefficientsgive modal coefficients.basis_report(orgenerator.report()) summarizes rank, conditioning, orthogonality and piston content.save/load(.npz) andsave_fits/load_fitsstore the modes together with the generator's parameters, thegenerate()options, KL eigenvalues and the aobasis version.
Reproducible. KL modes follow a fixed sign and degenerate-rotation convention: tip along +x, tilt along +y. The same geometry gives the same modes on every machine, CPU or GPU.
Tutorials and examples
tutorials/ holds eight Jupyter walkthroughs; see tutorials/README.md for a guide.
| Notebooks | |
|---|---|
| Getting started | 01 · Quickstart, 02 · A tour of the bases |
| Everyday use | 03 · Shaping a basis, 04 · Actuator geometry |
| In depth | 05 · KL and turbulence, 06 · Influence functions and DM KL, 07 · Calibration patterns, 08 · Saving and sharing |
examples/ holds ready-to-run scripts (each has --help):
python examples/make_m2c.py kl --grid-size 20 --n-modes 100 --remove tiptilt -o kl.fits --plot kl.png
python examples/dm_kl.py --n-modes 80 -o dmkl.fits
python examples/calibration.py
Performance
python examples/benchmark.py --grid-sizes 16 32 64 --n-modes 100 --gpu --markdown. Each entry is the best of 3 runs of generate(100) (zonal fast: its full pattern set) on a square grid clipped by a 10 m pupil.
Host: an 80-core Arm Neoverse-N1 server, using 4 cores (OPENBLAS_NUM_THREADS=4), and an NVIDIA RTX A400.
| Basis (100 modes) | 16×16 (172 acts) | 32×32 (740 acts) | 64×64 (3096 acts) |
|---|---|---|---|
| KL (CPU) | 0.023 s | 0.158 s | 1.99 s |
| KL (GPU) | 0.026 s | 0.161 s | 4.41 s |
| Zernike | 0.005 s | 0.011 s | 0.033 s |
| Fourier | 0.006 s | 0.024 s | 0.081 s |
| Hadamard | 0.001 s | 0.021 s | 0.142 s |
| Zonal | <0.001 s | <0.001 s | 0.002 s |
| Zonal fast (3-pitch spacing) | 0.005 s | 0.023 s | 0.120 s |
Full bases (--n-modes all) on 3096 actuators take 6.3 s for KL, 4.3 s for Zernike, 7.1 s for Fourier and 3.0 s for Hadamard. That includes the rank check.
Some notes on these numbers:
- KL costs O(N³). For a few modes the CPU uses a partial eigensolver, which is why 100 modes are faster than the full basis.
- The covariance is evaluated once per distinct actuator separation.
- The GPU path only pays off on GPUs with strong float64 throughput. The RTX A400 used here has little, and on such cards the CPU is as fast or faster.
Development and testing
git clone https://github.com/jacotay7/aobasis.git
cd aobasis
pip install -e ".[dev]"
pytest
CI runs the test suite on Python 3.8–3.14, on aarch64 and without matplotlib, runs every example script, and executes every tutorial notebook.
CI cannot run the GPU tests: they need CuPy and a CUDA device, and skip without them. Run them locally before changing GPU code:
pip install cupy-cuda12x
pytest -k gpu -rs # -rs shows a skip reason if no device is found
Contributing
Contributions are welcome. Open an issue to report a bug or propose a feature, or send a pull request with a test for the change and an entry in CHANGELOG.md.
Contact
Jacob Taylor, jacobataylor7@gmail.com
License
MIT; see LICENSE.
Metadata
Release files for aobasis 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aobasis-2.0.0.tar.gz | 64.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aobasis-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 111.7 kB
Release files / aobasis-2.0.0.tar.gz
| Download URL | aobasis-2.0.0.tar.gz |
|---|---|
| Size | 64.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a005cd6ccc3281e8af5ff06ee2db7bae41b3d785ab68b6ba97acaa596e765dc3
|
|
BLAKE2b-256 checksum How to use checksums |
e758281f637f0d01a774a0c0c2fe668174902b201a215a23afe1a357d996d215
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / aobasis-2.0.0-py3-none-any.whl
| Download URL | aobasis-2.0.0-py3-none-any.whl |
|---|---|
| Size | 47.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
426c7835a49015c9f0eb7cb5a18f726aa39fe7821784770b874cfc30c0615d76
|
|
BLAKE2b-256 checksum How to use checksums |
f4877db4c4987881db55adc67bd3b9e16759e8c1fe9eee1e2033e634ee51e3e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log