A phenology-aware moisture-stress and 8-day irrigation-advisory engine for canal command areas, built for the Bharat Antariksh Hackathon. It fuses real Sentinel-1 SAR and Sentinel-2 optical data with CHIRPS rainfall and ERA5 weather over a ~20×18 km pilot in Ludhiana, Punjab, and layers an absolute, growth-stage-aware stress index and a FAO-56 water-balance advisory on top of a Random Forest crop map.
Canal command areas need per-field, per-week guidance on when and how much to irrigate — not just a crop map.
Sentinel + Random Forest crop classification is a commodity baseline; the differentiating layer is stress detection and an advisory that stays coherent with it.
Relative stress anomalies mislead: a pixel must be judged against its own multi-year history, and flowering-stage crops need stricter thresholds than maturing ones.
Random pixel splits leak through spatially correlated neighbours, inflating accuracy claims.
Multi-source ingestion fuses Sentinel-2 optical (cloud-masked), Sentinel-1 SAR (speckle-filtered), CHIRPS rainfall, and ERA5 weather into 8-day temporal-median composites over a Punjab canal-command pilot.
Random Forest crop classification validated with 4-fold spatial hold-outs (kappa 0.67 ± 0.03), reported with per-class F1 and the no-information baseline rather than headline accuracy alone.
The core contribution is the stress layer: an absolute, stage-aware VCI index judging each pixel against its own multi-year NDVI envelope, with stricter thresholds during flowering, cross-checked against independent ERA5 soil moisture.
FAO-56 Kc water-balance engine converts crop demand minus effective rainfall into a three-level irrigation advisory that must stay coherent with observed VCI stress.
A swappable provider contract (generate_scene) supports synthetic sample mode, live Google Earth Engine mode, and a MODIS 250 m demo proving the method transfers unchanged across resolutions.
Outputs are georeferenced rasters (QGIS-ready .wld/.prj sidecars) plus a JSON summary, served through a FastAPI + Leaflet dashboard deployed on Render.
What I Built
Full pipeline from Google Earth Engine (Sentinel-2 SR with per-pixel cloud masking, Sentinel-1 GRD with speckle filtering, CHIRPS, ERA5) to 8-day composites, multi-temporal features, and phenology metrics (SOS/EOS/LGP).
Random Forest crop classification validated with 4-fold spatial hold-outs: Kappa 0.67 ± 0.03, macro-F1 0.77 ± 0.03, wheat F1 0.96 — with the ~89.6% 'always-wheat' no-information baseline reported beside overall accuracy.
An absolute, stage-aware VCI moisture-stress index: each pixel's NDVI scored against its own 2019–24 percentile envelope, blended with a canopy-water NDWI term, with stricter thresholds at flowering; recall ~0.86 / precision ~0.87 against injected stress in sample mode.
FAO-56 Kc water-balance irrigation advisory (demand minus effective rainfall with soil-storage carry-over) producing no-action / schedule-within-8-days / irrigate-now maps, where 'now' requires confirmed VCI stress.
Independent ERA5 soil-moisture (SMI) cross-check confirming the moisture layer responds to rainfall (r ≈ 0.32), and feature-importance analysis showing genuine S1+S2 fusion (SAR contributes ~23%).
A resolution-transfer demo running the identical pipeline on MODIS 250 m data, demonstrating the method scales to moderate-resolution national monitoring.
Georeferenced outputs (.wld/.prj sidecars, QGIS-ready) plus a FastAPI + Leaflet/Chart.js dashboard; 10 tests covering ~95% of the offline-testable code; deployed on Render serving a committed real-data snapshot.
Screenshots
Irrigation advisory map — no action / schedule within 8 days / irrigate nowRandom Forest crop classification over the Ludhiana pilot areaStage-aware VCI moisture-stress mapLatest 8-day NDVI composite from Sentinel-2
Key Decisions & Tradeoffs
Spatial hold-out validation over 4 folds instead of random pixel splits, with Kappa/macro-F1 as the headline because OA is inflated in an ~86%-wheat monoculture.
Honest labeling caveat front and center: reference labels are ESA WorldCereal (itself satellite-derived), so metrics measure model agreement, not field truth — with a GT_CSV hook already wired for real survey points.
A provider contract (generate_scene()) that swaps sample ↔ GEE ↔ future ISRO (Bhoonidhi/AWiFS) backends without touching the science modules.
Absolute VCI against each pixel's own multi-year history rather than relative anomalies, with stage-dependent thresholds.
All tunable coefficients (stress weights, Kc, thresholds) in config.py rather than magic numbers.
Why It Matters
It goes past the commodity crop-classification baseline to the layer that's actually useful — a validated stress signal driving a physically grounded irrigation recommendation — with the honest, spatially sound evaluation remote-sensing work usually lacks.
What I'd Improve Next
Validate against real field survey points via the already-wired GT_CSV hook, replacing WorldCereal's satellite-derived labels to break the ground-truth circularity.
Swap in indigenous data sources — AWiFS/LISS-III via Bhoonidhi, EOS-04/NISAR SAR, IMD rainfall grids — through the existing provider contract for the operational path.
Improve the weak heterogeneous other-crop class (F1 0.55) with better minority-class features or targeted sampling.
Calibrate the VCI multi-year baseline per sensor so the stress layer works at moderate (AWiFS/MODIS) resolution, not just Sentinel.
Scale from a single command area to district/state coverage by running the embarrassingly-parallel per-tile pipeline on a batch backend (Bhoonidhi/MOSDAC or a STAC + COG stack).