⚠️ Important Note
This project is actively under development. While the core functionality is production-ready and thoroughly tested, some advanced features are still being refined.
Physics-informed deep learning for InSAR phase unwrapping.
Why this exists · How it works · Install · Quickstart · Notebooks · Architecture · Citation
pyunwrap-insar unwraps Interferometric Synthetic Aperture Radar (InSAR) phase — the
core measurement behind satellite-based ground-deformation monitoring — using a
physics-informed U-Net that predicts an integer ambiguity map, not the
unwrapped phase itself. The rewrapping identity is enforced by construction,
so the model is structurally incapable of producing an output that
contradicts the observed wrapped phase; it can only be wrong about how many
2π cycles were missed, never about the physics of wrapping.
Why this exists
Every classical phase-unwrapping algorithm — branch-cut methods, minimum-cost
flow (the approach behind SNAPHU, the field's long-standing reference tool),
Goldstein's algorithm — rests on one assumption: that the true phase gradient
between adjacent pixels never exceeds π radians (the Nyquist/Itoh
condition). Two situations break that assumption in practice:
- Low coherence. Vegetation, water, and temporal decorrelation add near-random phase noise. Once the local gradient becomes unreliable, branch-cut and MCF methods don't just get that one pixel wrong — they propagate the error across the connected region downstream of it.
- Steep deformation gradients. Earthquakes, volcanic inflation, and
mining subsidence can produce genuine phase gradients that exceed
πradians per pixel near the source. No amount of algorithmic cleverness recovers this from the wrapped phase alone without an external prior — which is exactly the gap a learned model can fill.
pyunwrap targets both regimes directly, and does so without inheriting the
most common failure mode of naive deep-learning approaches to this problem:
regressing the unwrapped phase directly gives a network no reason to respect
wrap(prediction) == observed_phase. Predicting the integer ambiguity
instead makes that identity a mathematical guarantee, not a hope.
How it works
AmbiguityNet outputs a continuous ambiguity prediction, rounds it via a
straight-through estimator, and reconstructs phase directly:
φ̂ = ψ + 2π · round(k̂), k̂ ∈ ℤ
| Approach | Failure mode |
|---|---|
Regress φ directly |
Nothing constrains wrap(prediction) == ψ; the network can output any real value |
Predict k (this package) |
wrap(ψ + 2π·round(k̂)) == ψ holds by construction — the network only has to get the integer cycle count right |
That single design decision shapes everything downstream: training uses a
physics-informed loss with a component that's provably near-zero regardless
of prediction quality (documented explicitly, not hidden — see
pyunwrap/models/losses.py); tiled inference
merges the integer ambiguity map across overlapping patches, never the
phase itself, because averaging phase directly across a tile boundary can
silently produce a value that satisfies no physical interferogram.
Key features
Synthetic data engine (pyunwrap.synthetic)
— Gaussian subsidence bowls, a from-scratch Okada (1985) rectangular fault
dislocation model, a Mogi (1958) volcanic point source, DEM-driven
topographic phase, Kolmogorov-spectrum atmospheric turbulence, orbital
ramps, coherence-dependent decorrelation noise, and a pseudo-real strategy
that rewraps real L-band (ALOS-2) unwrapped phase into simulated C-band data
to help bridge the sim-to-real gap.
AmbiguityNet (pyunwrap.models)
— a ResNet-34-encoder U-Net with a dual head: the integer ambiguity map via
a straight-through-estimator rounding layer, and an auxiliary residue-
probability map for uncertainty. Trained with a four-component
physics-informed loss (ambiguity regression, re-wrap consistency,
coherence-weighted smoothness, ambiguity-map residue penalty).
Curriculum training (pyunwrap.training)
— a three-stage curriculum (high-coherence/low-gradient → moderate →
full difficulty), optional SNAPHU pseudo-ground-truth fine-tuning on real
data, AdamW with warmup/cosine annealing, and TensorBoard logging.
Production inference (pyunwrap.inference)
— tiled processing of arbitrarily large interferograms with edge-aware,
residue-probability-weighted smart merging of the ambiguity map, Monte
Carlo Dropout uncertainty, and an ONNX Runtime → OpenVINO backend fallback
chain for deployment without a PyTorch dependency.
Scientific analytics (pyunwrap.analytics)
— Goldstein-style residue detection and clustering, Nyquist
gradient-violation mapping, error-distribution statistics, Grad-CAM and
Integrated-Gradients explainability, and uncertainty-calibration
reliability diagrams.
Visualization & reporting (pyunwrap.visualization)
— interactive Plotly 3D phase surfaces and heatmaps, a folium
swipe-comparison map, and a self-contained, Jinja2-templated HTML report
tying every stage together.
Architecture
InSARSyntheticGenerator ──┐ real GeoTIFFs
│ (wrapped, coherence, amplitude)
▼ │
tiling + normalization ▼
│ tiled inference
▼ via PhaseUnwrapper
InSARTileDataset │
│ │
▼ ▼
Trainer.fit() ──── AmbiguityNet ──── smart ambiguity-map
(curriculum, (this is the merging (never
physics loss) same model) the phase)
│
▼
unwrapped phase +
analytics + report
See docs/architecture.md for the full
module-by-module reference and a longer explanation of the physics
invariant every stage is built around.
Installation
git clone https://github.com/yourusername/pyunwrap.git
cd pyunwrap
pip install -e .
Optional extras, installed as needed:
| Extra | Adds | Use case |
|---|---|---|
dev |
pytest, pytest-cov, black, ruff, mypy |
Development, testing, linting |
maps |
folium, leafmap |
Interactive map visualization |
deploy |
openvino, onnx, onnxconverter-common, onnxscript |
ONNX export, OpenVINO inference |
notebooks |
jupyter, ipykernel |
Running the example notebooks |
pip install -e ".[dev,maps,deploy,notebooks]" # everything
Quickstart
from pyunwrap.synthetic.generator import InSARSyntheticGenerator
from pyunwrap.models.ambiguity_net import AmbiguityNet
from pyunwrap.inference.unwrapper import PhaseUnwrapper
# Generate a synthetic training sample (Mogi volcanic source deformation).
gen = InSARSyntheticGenerator(size=256, seed=42)
sample = gen.generate_sample(deformation_type="mogi")
# Run tiled inference on a real interferogram with a trained model.
model = AmbiguityNet(pretrained=False, k_max=10.0) # or load your own checkpoint
unwrapper = PhaseUnwrapper(model=model, device="cuda")
result = unwrapper.unwrap(
wrapped_phase_path="data/wrapped_phase.tif",
coherence_path="data/coherence.tif",
amplitude_path="data/amplitude.tif",
tile_size=512, overlap=64,
generate_report=True,
)
result.save_geotiff("unwrapped_output.tif")
Training a model end to end:
pyunwrap-train \
--train-hdf5 train_tiles.h5 --val-hdf5 val_tiles.h5 \
--epochs 60 --warmup-epochs 5 \
--finetune-hdf5 snaphu_pseudo_gt.h5 --finetune-start-epoch 55 \
--out-dir runs/pyunwrap_v1
Notebooks
Two notebooks in notebooks/ walk through the package
hands-on, checked in pre-executed with real outputs so they're readable
without running anything:
01_training_pipeline.ipynb— the complete training chain: synthetic data, tiling,AmbiguityNet+Trainer, training curves, and predicted-vs-ground-truth comparison.02_full_pipeline.ipynb— the complete end-to-end chain: a deformation-model gallery, tiling and augmentation visualized, a full curriculum training run with every loss component plotted, tiled inference on real GeoTIFFs, residue/Nyquist/error analytics, Grad-CAM and Integrated-Gradients explainability, 3D and interactive-map visualization, ONNX deployment with a numerical PyTorch-vs-ONNX agreement check, and the final HTML report.
pip install -e ".[dev,maps,notebooks]"
jupyter notebook notebooks/
Testing
pytest -m "not slow" # fast unit + integration tests
pytest # full suite, including the end-to-end
# synthetic → train → infer → report test
pytest --cov=pyunwrap --cov-report=term-missing
The suite includes known-answer physics tests (e.g. residue detection is
checked against a hand-constructed phase vortex with an exact, known
topological charge — not just "runs without crashing") and a tile-merging
regression test that asserts tiled-and-merged inference is numerically
identical to a whole-image pass, directly targeting the class of bug where
tile boundaries silently corrupt the output. See
CONTRIBUTING.md for the full breakdown and development
setup.
Project status
Early-stage and actively developed. The pipeline — synthetic data
generation, training, tiled inference, analytics, and reporting — is
implemented and tested end to end, but no pretrained weights ship yet;
from_pretrained() downloads from a Zenodo record you supply, and the
example notebooks train small demo models from scratch rather than loading
a benchmarked checkpoint. Monte Carlo Dropout uncertainty is currently a
no-op (AmbiguityNet has no nn.Dropout layers yet, only BatchNorm) —
tracked as a known gap, not hidden. APIs may change between minor versions
until 1.0. See CHANGELOG.md for what's landed so far.
Relationship to the wider EO stack
pyunwrap works standalone, but is designed to eventually sit downstream of
pygeofetch (interferogram acquisition/formation) and alongside
ps-gnn (persistent scatterer identification) in a broader open-source
InSAR processing stack.
Citation
If pyunwrap is useful in your research, please cite it:
@software{pyunwrap2026,
title = {pyunwrap: Physics-Informed Deep Learning for InSAR Phase Unwrapping},
author = {{pyunwrap contributors}},
year = {2026},
url = {https://doi.org/10.5281/zenodo.22209219},
note = {Version 0.1.1}
}
References
- Goldstein, R. M., Zebker, H. A., & Werner, C. L. (1988). Satellite radar interferometry: Two-dimensional phase unwrapping. Radio Science, 23(4).
- Itoh, K. (1982). Analysis of the phase unwrapping algorithm. Applied Optics, 21(14).
- Chen, C. W., & Zebker, H. A. (2001). Two-dimensional phase unwrapping with use of statistical models for cost functions in nonlinear optimization (SNAPHU). JOSA A, 18(2).
- Okada, Y. (1985). Surface deformation due to shear and tensile faults in a half-space. Bulletin of the Seismological Society of America, 75(4).
- Mogi, K. (1958). Relations between the eruptions of various volcanoes and the deformations of the ground surfaces around them. Bulletin of the Earthquake Research Institute, 36.
Contributing
Contributions are welcome — bug reports, documentation, new deformation
models, or core improvements. See CONTRIBUTING.md for
development setup, test/lint conventions, and the design principles worth
knowing before touching the physics-critical modules.
License
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 pyunwrap_insar-0.1.1.tar.gz.
File metadata
- Download URL: pyunwrap_insar-0.1.1.tar.gz
- Upload date:
- Size: 90.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ae0a4d38926f1605aa87df4bf8e71717fbdd4a38b69ba161494ec741b4d18f9
|
|
| MD5 |
f17104aa505995377710a18aa5136c88
|
|
| BLAKE2b-256 |
2abcee79bd087a806e6f13aa90406138ef25b31b4653fa223f044caf05ca7f0f
|
File details
Details for the file pyunwrap_insar-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pyunwrap_insar-0.1.1-py3-none-any.whl
- Upload date:
- Size: 81.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9fc7683362e902f16bb51676702500d674d15e2028795812cb8f28ee7e9d810
|
|
| MD5 |
683cf1bde16f19a3c0fdd25f212b51d2
|
|
| BLAKE2b-256 |
6e5a65db31380f0b919b8ae8ccc75a36e6961e02a049b7ac9d982cc242ed752c
|