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 four steps in order:
python generate_samples.py ... # Stage 1: synthesize wafers
# -> 1_samples/target_file.csv,
# 1_samples/ground_truth.csv, ...
python -m wlzpoly.decompose --solver lsq ... # Stage 2a: LSQ fit
# -> 2_decomposition/decomposed_targets_lsq.csv
python -m wlzpoly.decompose --solver ridge --auto_lam ...
# Stage 2b: Ridge fit with LOOCV
# -> 2_decomposition/decomposed_targets_ridge.csv
python -m wlzpoly.verify ... # Stage 3: read both CSVs + ground_truth,
# compare, plot (no fitting)
Every parameter is a CLI flag — --working_folder, --wafer_points, --input_file, --output_file, --auto_lam, --col_wafer_id, --col_points, --coeff_prefix, --decomposed_lsq_file, --decomposed_ridge_file, --ground_truth_file, --n_terms, --solver, etc. (wlzpoly.reconstruct uses --input_folder, --wafer_point_json, --decomposed_file instead — see its section below.) See python -m wlzpoly.decompose -h / verify -h / reconstruct -h for the full list. Demo outputs land in examples/{1_samples, 2_decomposition, 3_verification, 4_reconstruction}/; pre-generated copies are visible on the GitHub repo.
Optional — wlzpoly.reconstruct
Inverse of decompose: pushes fitted coefficients back through the basis matrix to rebuild the N-point measurement profile (T = A·a). No R² / no ground-truth comparison — production / inference use case where the true T is unknown.
python -m wlzpoly.reconstruct `
--decomposed_file decomposed_targets.csv `
--wafer_point_json wafer_points.json --n_terms 9 `
--output_folder ./4_reconstruction
CLI options are split into Input (--input_folder, --wafer_point_json, --decomposed_file, --n_terms, --coordinate, --col_wafer_id, --col_points, --coeff_prefix, --coeff_suffix) and Output (--output_folder, --output_file) argparse groups. --coeff_suffix (default "") lets you read ML-pipeline CSVs whose coefficient columns carry trailing tags like _pred / _true (columns are read as <prefix><j><suffix> and stripped internally).
Python API: wlzpoly.reconstruct.reconstruct(...) returns a pd.DataFrame (index = wafer_id, columns = P1..PN); the CLI handles CSV writing.
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.2.tar.gz.
File metadata
- Download URL: wlzpoly-0.0.2.tar.gz
- Upload date:
- Size: 34.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c8d555af52331019a42ebe4916dfe844c26464b6709651fceb1fa6b3e12e10d
|
|
| MD5 |
3251ba934962d4e1b7b087865261900d
|
|
| BLAKE2b-256 |
0d93ab9afa90806991e2e89b800215d5aac872efd156ffb91be51855986d289f
|
File details
Details for the file wlzpoly-0.0.2-py3-none-any.whl.
File metadata
- Download URL: wlzpoly-0.0.2-py3-none-any.whl
- Upload date:
- Size: 31.9 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 |
d8c152bdd3ec1c59e7936a53a83573067ff945fc5f1b81cc8466efb0c71f3549
|
|
| MD5 |
40213c156187fa0d6a01527604afa1be
|
|
| BLAKE2b-256 |
81c215c96d40e3a92ff10aef806543a6d078351729d74f831301efbc0823d092
|