strait — satellite vessel detection & port activity monitoring
A Python package for detecting vessels from Sentinel-1 SAR imagery and measuring port activity from satellite data — any port, any time.
The one thing
import strait
cutout = strait.Cutout(
module="sentinel1",
x=slice(103.4, 104.6),
y=slice(1.0, 1.6),
time=slice("2021-01", "2026-09"),
)
cutout.prepare() # download + process scenes
detections = cutout.detect() # CFAR vessel detection
monthly = cutout.aggregate(detections, zones={"eastern": (104.0, 1.24, 104.35, 1.40)})
That gives you monthly vessel counts per zone from free satellite radar.
Why this exists
Ports publish trade statistics with a 2-4 week lag. Satellite radar sees ships at anchor immediately, day or night, cloud or clear. This package turns that satellite data into economic indicators.
It was built for the Singapore Strait Observatory project, where radar-derived anchorage presence explains 48% of bunker sales variance (R²=0.478, detrended, weather-robust, validated against AIS).
Install
pip install strait-observatory
What it does
| Layer | What | Output |
|---|---|---|
Cutout |
Spatial/temporal subset + data source abstraction | xarray Dataset |
detect() |
Vessel detection (trimmed CFAR) | GeoDataFrame of detections |
aggregate() |
Zone × time aggregation | Monthly/weekly/daily counts |
AIS |
Validation against live/historical AIS | Precision/recall metrics |
Stats |
Join with official trade statistics | Correlation results |
Data sources
| Source | What | Auth |
|---|---|---|
| Copernicus Sentinel-1 | SAR radar imagery | Free CDSE account |
| AISStream.io | Live vessel AIS | Free API key |
| AISHub.net | Community AIS | Free membership |
| Mendeley (historical) | Port AIS datasets | Open download |
| S2Coast-2023 | 10m coastline (land mask) | Zenodo, open |
Quick start
pip install strait-observatory
export CDSE_USER=your@email
export CDSE_PASSWORD=your_password
import strait
# 1. Define your area and time
cutout = strait.Cutout(
module="sentinel1",
x=slice(103.4, 104.6), # longitude
y=slice(1.0, 1.6), # latitude
time=slice("2021-01", "2026-09"),
)
# 2. Download and process (first time takes ~1h for 5 years)
cutout.prepare()
# 3. Detect vessels
detections = cutout.detect(method="trimmed_cfar")
# 4. Define anchorage zones (or use built-in Singapore zones)
zones = strait.Zones.singapore_strait()
monthly = cutout.aggregate(detections, zones, freq="MS")
# 5. Validate against AIS (optional)
ais = strait.AIS(source="aisstream", api_key="...")
match = ais.match(detections, threshold_m=500)
# 6. Correlate with official statistics (optional)
stats = strait.Stats.from_datagov_sg()
results = stats.correlate(monthly, target="bunker_sales")
Architecture (inspired by atlite)
strait/
├── __init__.py # exports Cutout, detect, aggregate, AIS, Stats
├── cutout.py # Cutout class (spatial/temporal abstraction)
├── detect/
│ ├── __init__.py # detect() dispatcher
│ ├── cfar.py # classic CFAR (v3.1)
│ ├── trimmed_cfar.py # trimmed CFAR (v4, from SAR literature)
│ └── land_mask.py # coastline-based land mask
├── data/
│ ├── __init__.py # data source registry
│ ├── sentinel1.py # Sentinel-1 via CDSE (Sentinel Hub + OData)
│ ├── ais.py # AIS from multiple sources
│ └── official.py # Official statistics (data.gov.sg, etc.)
├── aggregate.py # zone × time aggregation
├── validate.py # SAR-AIS matching, precision/recall
├── stats.py # econometric correlation
└── zones.py # built-in zone definitions
Built-in zones
# Singapore Strait (from the observatory project)
zones = strait.Zones.singapore_strait()
# Define your own
zones = strait.Zones({
"my_anchorage": (104.0, 1.24, 104.35, 1.40), # lon_min, lat_min, lon_max, lat_max
"port_area": (103.68, 1.20, 104.02, 1.34),
})
License
MIT
Citation
If you use this in research, cite the Singapore Strait Observatory:
@software{strait_observatory_2026,
title = {strait: satellite vessel detection and port activity monitoring},
author = {Sivasubramanian, S.},
year = {2026},
url = {https://github.com/siva-sub/strait}
}
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 strait_observatory-0.1.0.tar.gz.
File metadata
- Download URL: strait_observatory-0.1.0.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ff7df223a5587dc8a5cf76fcc06af943c93b43833bd1b9fdc65c894c72f0dc9
|
|
| MD5 |
a82a6eae47ee056aa34ed432efcddff5
|
|
| BLAKE2b-256 |
83e1e6e3f372c12dac1e8cc601717b17dd0e617065b9650d07342147e8c7da36
|
File details
Details for the file strait_observatory-0.1.0-py3-none-any.whl.
File metadata
- Download URL: strait_observatory-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15184055b8f76466795fac240d82eeb6a241727322282a6a22188cb7955600a0
|
|
| MD5 |
37e2ece635b05a0471e860d1f5e244f1
|
|
| BLAKE2b-256 |
cce3652be8ea627afebcadb899171f42dc751d01b551d937a42cda5261cbcf9f
|