Wafer-level Zernike polynomial decomposition and fitting
Project description
wlzpoly — Wafer-Level Zernike Polynomials
Decompose 13-point wafer thickness measurements into 9 Zernike coefficients (LSQ / Ridge), with a reproducible demo workflow that generates synthetic data, fits it, and verifies the recovered coefficients against ground truth.
Install
pip install wlzpoly
Requires Python 3.9+. Dependencies: numpy >= 1.22, pandas >= 1.5, matplotlib >= 3.5, tqdm >= 4.60.
Quick start
import numpy as np
from wlzpoly import ZernikePolynomials, WaferLevelZernikePolynomials
# 1) Build a wavefront from known coefficients (Noll j -> a_j)
z = ZernikePolynomials(coeffs={1: 500.0, 4: -12.0, 6: 0.5}, n_terms=9)
field = z.evaluate(rho=np.array([0.0, 0.5, 1.0]),
theta=np.array([0.0, 0.0, 0.0]))
# 2) Fit Zernike coefficients from measurements at known coordinates
# coords_df : DataFrame indexed by point_id, columns ['x','y'] (mm),
# attrs['wafer_radius_mm']
# df_measured : DataFrame indexed by MultiIndex(wafer_id, point_id),
# column ['T']
wlz = WaferLevelZernikePolynomials(
coords_df=coords_df, coordinate="cartesian", n_terms=9,
)
fit_results = wlz.fit_coefficients(mesured_df=df_measured, solver="lsq")
# fit_results : list of {"id": <wafer_id>, "coeffs": np.ndarray}
# 3) Render a fitted wafer field
fig = wlz.draw_field(coeffs=fit_results[0]["coeffs"])
fig.savefig("W_01_fit.png", dpi=130, bbox_inches="tight")
ZernikePolynomials follows the Noll convention and supports any radial order — the j -> (n, m) mapping is computed dynamically.
Public API
from wlzpoly import (
ZernikePolynomials, # pure-math + per-wavefront instance
WaferLevelZernikePolynomials, # wafer-aware (coords + measurements -> fit)
fit_lsq, fit_ridge, # general-purpose linear solvers
)
| Function / class | Purpose |
|---|---|
ZernikePolynomials.basis(j, rho, theta) |
Single Zernike basis Z_j(rho, theta) |
ZernikePolynomials.basis_matrix(rho, theta, n_terms=...) |
Design matrix A for fitting |
ZernikePolynomials.pyramid_image(n_max=..., names=..., return_type=...) |
Zernike pyramid PNG / Figure |
ZernikePolynomials(coeffs=...).evaluate(rho, theta) |
Evaluate a specific wavefront |
WaferLevelZernikePolynomials(coords_df, coordinate, n_terms) |
Pre-compute A from measurement layout |
wlz.fit_coefficients(mesured_df, solver, lam) |
Per-wafer LSQ / Ridge fit |
wlz.draw_field(coeffs) |
Heatmap with measurement-point overlay |
fit_lsq(A, T) |
a_hat = (A^T A)^-1 A^T T |
fit_ridge(A, T, lam) |
a_hat = (A^T A + lam I)^-1 A^T T |
loocv_lambda(A, T, lambdas) |
LOOCV-driven lambda selection |
wlzpoly.decompose.load_wafer_coordinates(wafer_points_file, coordinate) |
Read points JSON into a DataFrame |
wlzpoly.decompose.load_measured_data(target_file) |
Read target CSV into long-format DataFrame |
Three-stage demo (after development install)
git clone https://github.com/ykim2718/WaferLevelZernikePolynomials.git
cd WaferLevelZernikePolynomials
pip install -e .
cd examples
.\run_demo.ps1 # runs all three stages
run_demo.ps1 invokes the three stages in order:
python generate_samples.py ... # Stage 1: synthesize wafers
# -> samples/target_file.csv,
# samples/ground_truth.csv, ...
python -m wlzpoly.decompose --target_file ... # Stage 2: fit Zernike coefficients
python -m wlzpoly.verify --target_file ... # Stage 3: compare vs ground truth
--ground_truth_file ...
Every parameter is a CLI flag — --working_folder, --wafer_points, --target_file, --ground_truth_file, --n_terms, --solver, etc. See python -m wlzpoly.decompose -h / verify -h for the full list. Demo outputs land in examples/{samples,decomposition,verification}/; pre-generated copies are visible on the GitHub repo.
Documentation
Full documentation — folder layout, CLI options, configuration files, output schemas, scenario reference, recipes, algorithm summary — lives on the GitHub README:
https://github.com/ykim2718/WaferLevelZernikePolynomials
Links
- Source / docs: https://github.com/ykim2718/WaferLevelZernikePolynomials
- Issues: https://github.com/ykim2718/WaferLevelZernikePolynomials/issues
- License: MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wlzpoly-0.0.1.tar.gz.
File metadata
- Download URL: wlzpoly-0.0.1.tar.gz
- Upload date:
- Size: 27.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a057abf95e26e9cd51712890b82179f68f2214be68e510d073c660fec435a609
|
|
| MD5 |
6fdbba9758ab327838059a2574f3353f
|
|
| BLAKE2b-256 |
1aed835f0c0f50ba5aa5898e2fc8899cf58ef4f14e96ffd359c4a39382770c3d
|
File details
Details for the file wlzpoly-0.0.1-py3-none-any.whl.
File metadata
- Download URL: wlzpoly-0.0.1-py3-none-any.whl
- Upload date:
- Size: 24.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7225ec68e30032fc59f49e32f09a489e4af2d3d81700d4166f48937a6c4c60d7
|
|
| MD5 |
fdb46fdb67ce8ebd13442888a884b0d5
|
|
| BLAKE2b-256 |
f1aea1f4e5b4881ebb281e322a1d69b276320be5da04517922b232b33fa9ca4a
|