Optical design, analytical modeling, and 3D ray-tracing simulations for the transparent polygon prism laser scanner known as Hexastorm.
This package provides the optical calculations used by:
- Hexastorm Design: github.com/hstarmans/hexastorm_design
- Hexastorm FreeCAD Workbench: github.com/hstarmans/freecad_hexastorm
- Hackaday Project: hackaday.io/project/21933-open-hardware-transparent-polygon-scanner
- Video Walkthrough: YouTube Explanation
-
Analytical Model (
prisms.analytical)- Computes diffraction-limited Gaussian beam waist spot size and Rayleigh range.
- Calculates longitudinal and transversal focus shift through rotating polygon facets.
- Computes 3rd-order Seidel aberrations (spherical, coma, astigmatism) and Strehl ratio based on Wyant's optical testing formulations.
- Analyzes scanline duty cycle, non-uniform sweep velocity, and cross-scan facet-to-datum errors.
-
Ray-Tracing Simulation (
prisms.system&prisms.library)- Non-sequential 3D ray tracing using upstream pyOpTools.
- Models N-BK7 polygon prisms, Edmund Optics cylindrical lenses, fold mirrors, and photodiode detection targets.
- Automatically determines synchronization photodiode hit angles (
find_object('diode')) and focal plane positioning.
-
Modern Interactive Notebooks (
Notebooks/)- Marimo Reactive App: Launch interactive simulations with live sliders via
uv run marimo edit Notebooks/marimo_plot_system.py. - Standard Python / Jupytext: Compatible with JupyterLab, VS Code, or direct terminal execution.
- Marimo Reactive App: Launch interactive simulations with live sliders via
This repository uses uv for fast, reproducible, and modern dependency management.
pyoptools compiles Cython/C++ extensions against the header-only C++ Eigen3 library (<Eigen/Dense>).
- Zero-sudo (User Local - Recommended):
Eigen is header-only and can be placed in
~/.local/include/eigen3:mkdir -p ~/.local/include/eigen3 curl -sL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz | tar -xz -C ~/.local/include/eigen3 --strip-components=1 export EIGEN3_INCLUDE_DIR="$HOME/.local/include/eigen3"
- System Package (Alternative if you have sudo):
sudo apt install -y libeigen3-dev
Clone the repository and synchronize the environment:
# Sync core dependencies and dev/notebook groups
uv sync --all-groupsTo install this package in editable mode in an external project (such as hexastorm_design):
uv add --editable /path/to/opticaldesignRun the complete automated test suite with pytest:
uv run pytest -vLint and format code using ruff:
uv run ruff check .
uv run ruff format .Launch the reactive Marimo application:
uv run marimo edit Notebooks/marimo_plot_system.pyOr run as a web app:
uv run marimo run Notebooks/marimo_plot_system.pyYou can run the notebook scripts directly via uv:
uv run python Notebooks/plot_system.py
uv run python Notebooks/system_compact.pyOr launch JupyterLab:
uv run jupyter labKey optical relationships implemented in prisms.analytical:
- Gaussian Waist Radius:
waist = (2 × wavelength / π) × f_numb - Rayleigh Length:
rayleigh_length = π × waist² / wavelength - Longitudinal Focus Shift:
slong = ((n - 1) / n) × T - Transversal Focus Shift:
disp = T × sin(x) × (1 - cos(x) / sqrt(n² - sin²(x))) - Duty Cycle:
duty_cycle = max_recommended_angle / max_angle_incidence - Strehl Ratio: Derived from wavefront aberration polynomial RMS optical path difference (OPD).
opticaldesign/
├── src/prisms/
│ ├── __init__.py # Top-level exports (PrismProperties, PrismScanner, Polygon)
│ ├── analytical.py # Closed-form physics formulas, aberrations, and Strehl calculations
│ ├── library.py # Custom pyOpTools components (regular Polygon prism)
│ └── system.py # Complete optical system layout and ray-tracing routines
├── Notebooks/
│ ├── marimo_plot_system.py # Interactive reactive Marimo notebook
│ ├── plot_system.py # Full scanner simulation (py:percent format)
│ └── system_compact.py # Compact layout & Fresnel reflection analysis
├── tests/
│ ├── test_analytical.py # Analytical formulas unit tests
│ ├── test_library.py # Polygon geometry tests
│ └── test_system.py # Ray propagation & diode hit detection tests
├── old/ # Archived 2017 RayOpt comparison scripts
├── pyproject.toml # Standard PEP 621 configuration managed by uv
└── uv.lock # Fully pinned, reproducible lockfile
GPL-3.0-or-later.