Polypix#
What is the coverage performance of my satellite constellation, or what is the revisit?
Polypix helps answer those questions. Provide batches of spherical regions and it hands back standard HEALPix cell IDs, which you then use for coverage maps, visibility counts, and revisit analysis.
Why Polypix#
The library was designed for mission analysis:
Everything takes batches. Whole arrays of regions go in, and what comes back is a NumPy array, not a Python object per region.
The grid has cells of equal area, so per-cell counts can be compared without weighting anything by latitude.
It is fast. The geometry runs in Rust, and large calls release the GIL and use several cores. Both case studies below cover millions of cells in well under a second.
The grid#
Polypix uses a HEALPix grid. HEALPix divides the sphere into cells of exactly equal area, starting from 12 cells and splitting each one into four at every step up in resolution. Each cell has an integer ID, and those IDs are what Polypix gives back.
Resolutions 0 to 3. Polypix goes to 29, where a cell is about 12 mm across on the ground. Resolutions has the whole table.#
A first example#
Suppose you have two circular ground footprints, one near Brussels and one near Bogotá. Polypix works in Cartesian directions instead of longitude and latitude, so the example converts them on the way in:
>>> import numpy as np
>>> import polypix as px
>>> def unit_vector(lon_deg, lat_deg):
... lon, lat = np.radians(lon_deg), np.radians(lat_deg)
... return np.stack(
... [np.cos(lat) * np.cos(lon), np.cos(lat) * np.sin(lon), np.sin(lat)],
... axis=-1,
... )
>>> centers = unit_vector([4.4, -74.1], [50.8, 4.6]) # Brussels, Bogota
>>> radii = np.deg2rad([5.0, 8.0]) # footprint half-angles
>>> coverage = px.cover_cap(centers, radii, resolution=8)
>>> np.diff(coverage.offsets)
array([1500, 3829])
At resolution 8 a typical cell is about 25 km across, which is why the smaller
footprint came back with 1500 cells and the larger one with 3829. The IDs themselves are available per footprint, as coverage[0] and coverage[1]:
>>> coverage[0][:4]
array([68085, 68086, 68087, 68088])
Those are standard HEALPix RING indices in a NumPy int64 array.
Showcases#
What Polypix doesn’t do#
Everything upstream of the geometry stays in your own code. Orbit propagation, attitude, sensor models, and ellipsoid intersection all happen before Polypix sees anything; what you hand over are the caps or footprints that come out of them.