SPPI spectral index
SPPI physics-based PV index: tested, not adopted for detection (2026-07-29)¶
SUPERSEDED in its title claim (as of 2026-08-11)
SPPI is now deployed nationally, as the corroborating half of the roofclf-AND-SPPI gate that sets an internal floor on the evidence atlas's headline figure. Two of this doc's conclusions do still hold: SPPI cannot serve as a standalone capacity instrument, and adding it as a roofclf feature changes nothing. Its segmentation comparison figures should not be reused -- they came from a non-production raster scored over an all-sizes population, and a later audit measured the production checkpoint at 0.761-0.775 AUC on buildings at or above 400 m².
Evaluation of He et al. 2026, "Spectral-Feature-Driven photovoltaic Detection: A universal
Physics-Based index for rapid Localization" (Int. J. Applied Earth Obs. Geoinf. 147, 105164,
doi:10.1016/j.jag.2026.105164) -- todo.md item 12. Reproduce with
.pixi/envs/default/bin/python scripts/sppi_index_test.py.
The paper proposes SPPI, a zero-parameter spectral index:
SPPI = (B01/B03) * (B11 - B03 - |B08 - B03| - |B12 - B03|) / (B11 + B03)
a visible "blue-shift" amplifier times a SWIR background-suppression term, combined
multiplicatively as a spectral AND. B01 is not in earthpv's 10-band composites
(LOCAL_BANDS drops B01/B09), so we substitute B02 -- the paper's own recommendation,
which it puts at ±2% accuracy cost.
Measured on our nine mapped quadrats¶
Scored per building over data/roofclf/buildings.geoparquet (roof-mean reflectance vs
exhaustively mapped PV), which is the sub-400 m2 regime we care about. _ws is
the within-roof-size-band AUC this project treats as the honest number.
| signal | median AUC | median AUC within size band |
|---|---|---|
| SPPI (zero training) | 0.823 | 0.828 |
| SPI (Tian 2022, the paper's baseline) | 0.819 | 0.782 |
| NDPI | 0.789 | 0.740 |
| our fraction head | 0.702 | 0.704 |
| our segmentation raster | 0.511 | 0.501 |
| our roof classifier (17 features, fitted) | 0.874 | 0.842 |
Two results matter here.
SPPI beats both of our trained model rasters, with no training at all. In
karachi_coast -- the Rule-1-complete quadrat where the segmentation model scores exactly
0.500 and predicts 0.0 m2 of PV against 13,964 m2 mapped -- SPPI scores
0.755/0.723. It is not blind where our detector is. That is a real finding and it
independently corroborates the roof-classifier ablation's conclusion that per-footprint
reflectance carries the small-array signal (0.841 alone) while the detection rasters do
not.
But it adds nothing to the shipped classifier, because that classifier already contains every band SPPI is built from, with fitted rather than hand-specified weights:
| feature set | median AUC | within size band |
|---|---|---|
| default (17 features) | 0.8736 | 0.8423 |
| default + SPPI | 0.8734 | 0.8377 |
log_roof_area + SPPI only (2 features) |
0.8351 | 0.8231 |
Adding SPPI moves the headline metric by -0.005, i.e. nothing, in the same
within-noise band as the seg/frac raster features. So: no change to roofclf's default
feature set. Worth recording that SPPI is a very efficient compression of that
information -- two features reach 0.823 where seventeen reach 0.842 -- which is what makes
the cold-start use below attractive.
The paper's claimed advantage over the older SPI partly reproduces: nearly identical on raw AUC (+0.004) but a genuine +4.6 points on the size-conditional metric, so its refinements do buy something specifically on small roofs.
Follow-up (2026-07-29): can SPPI carry capacity on its own? No.¶
Prompted by the proposal to build an SPPI-only density estimator, bypassing the foundation model. AUC measures ranking; capacity needs area, so this needed a separate test.
SPPI's correlation with each footprint's true PV areal fraction has median Pearson
r = 0.42 (r2 = 0.18). That is better than the fraction head's r = 0.22, but it
still leaves ~82% of the variance in how much PV a roof carries unexplained. Aggregate
predicted-over-true PV area, leave-one-quadrat-out, i.e. the same scale column
roofclf.exp_scale_anchor reports:
| quadrat | stratum | SPPI scale |
|---|---|---|
| Lahore DHA | 1 affluent residential | 0.261 |
| Multan | 6 industrial | 0.270 |
| Sundar | 6 industrial | 0.303 |
| SITE Karachi | 6 industrial | 0.377 |
| Faisalabad | 6 industrial | 0.431 |
| Karachi coastal | 1 affluent residential | 0.574 |
| Mardan | ⅓ planned residential | 0.928 |
| Sialkot | 2 dense old urban | 2.218 |
| Quetta | 5 arid / bare-land | 4.678 |
18x spread, so SPPI cannot be a standalone capacity instrument -- better than the fraction head's 49x, but nowhere near a publishable single constant, and it fails the same way for the same reason: no per-stratum intercept exists.
The specific failure mode is disqualifying for our geography. SPPI's worst
over-prediction, 4.7x, is in the arid quadrat -- bare ground reading as PV, which is
already earthpv's dominant false-positive mode and the entire reason
plausibility.py exists. SPPI's SWIR background-suppression term was supposed to kill
exactly that class and does not. Pakistan is largely arid, and the regions whose numbers
are already least trustworthy (Balochistan, Gilgit-Baltistan) are the arid ones, so
deploying SPPI nationally without a stratum correction would make the worst existing
problem worse, not better.
This also retracts the corroborator suggestion made above. The previous section proposed
using SPPI to adjudicate whether Gilgit-Baltistan's 288 no_building candidates are real.
It cannot: sharing the bare-ground failure mode means SPPI firing there is not independent
evidence of PV, only evidence that bright arid ground fools spectral methods generally.
Glint remains the genuinely independent channel, because its physics (specular geometry) is
unrelated to broadband brightness.
But it is strongly complementary, which is the real finding¶
Both detectors flagging their own top-K buildings (K = the true PV-building count per quadrat, a matched operating point), share of true PV area captured:
| median | |
|---|---|
| fraction head alone | 42.3% |
| SPPI alone | 61.4% |
| both agree | 30.6% |
| SPPI only (the increment) | 17.7% |
| union | 73.1% |
They overlap on only 30.6% of the area, so they are substantially independent detectors, and the union captures +30.8 points more true PV area than the fraction head alone. That is a real, large complementarity effect and it is the one part of the SPPI-in-parallel proposal that the data supports.
Complementarity does not mean 'add it to the total'
The headline est_mwp_rc is already recall-corrected: calibrated detected area
divided by measured per-bin recall. The PV a second detector would find is therefore
already in the published number, carried by the 1/recall multiplier. Adding an
SPPI-derived capacity on top double-counts it.
The correct operation is to combine the detectors, then re-measure recall of the
combined detector. Recall rises, so the divisor rises too, and the estimate can move
in either direction or barely move at all. The payoff is not a bigger number -- it is
a more defensible one. Today the small-size bins carry recall of roughly 3-33%, so
est_mwp_rc leans on a 3-30x extrapolation there; lifting measured area capture from
~42% to ~73% shrinks how much of the answer is extrapolation rather than measurement.
That is worth doing on its own terms, and it is a different goal from increasing
capacity.
On routing SPPI to urban areas specifically¶
The measurement does not support this. SPPI vs the shipped classifier, within size band, on the four urban/residential quadrats: Sialkot 0.842 vs 0.770 (SPPI +7.2), Mardan 0.681 vs 0.661 (+2.0), Lahore 0.747 vs 0.762 (-1.5), Karachi coastal 0.723 vs 0.846 (-12.3). So two favour SPPI, two favour the classifier, and the largest single gap favours the classifier -- in the Rule-1-complete quadrat, the one with trustworthy negatives.
A more specific pattern is weakly visible: SPPI leads in dense older/informal fabric (Sialkot) and trails badly in affluent planned housing (Karachi coastal). A roof-material homogeneity story would explain that, but it rests on n=1 quadrat per side and the two strata are not separable by any label the density stage currently carries. Not enough to route on.
Where it is worth adopting: cold start, not detection¶
The case is not accuracy, it is not needing a trained model. Our pipeline requires a checkpoint, a GPU, and OSM labels to reach a new region; SPPI needs one arithmetic pass over five bands. Concrete uses, none of which is "improve the detector":
- New-AOI reconnaissance. ~0.82 AUC immediately in a country with no labels and no
trained model, before
labels/chips/trainare viable. Fitsscripts/new_region.py's preflight role. - ~~An independent corroboration channel for the Gilgit-Baltistan question.~~ Retracted by the arid-quadrat result above -- SPPI over-predicts 4.7x on bare ground, so it shares the failure mode it would have been adjudicating. Use glint instead.
- A second detector in a recall-raising ensemble -- the complementarity result above (42% -> 73% of true PV area captured) is the strongest case in this document, with the caveat in the danger box: it buys a less-extrapolated estimate, not a larger one.
- Re-ranking, as another
rank_scoreterm. Lower priority: candidate polygons are already >= 400 m2 where our own confidence is decent, so this is the regime SPPI adds least to.
What it does not solve¶
It does not reach below our detection floor as a segmentation/polygon detector. The
paper states a 3x3-pixel minimum, which at Sentinel-2's 10 m GSD is ~900 m2 --
above earthpv's existing 400 m2 floor, not below it. The 0.828 above is a
per-building classification score on footprints we already have, not evidence that SPPI
can delineate an 86 m2 array. For the sub-400 m2 front, it is another
per-building instrument alongside roofclf, and a slightly weaker one.
Caveats on the paper's own numbers¶
- Its urban/rooftop results are not Sentinel-2-alone. Fig. 12's small-installation detection uses imagery fused with GaoFen-2 at 0.8 m. The rooftop claims do not transfer to an S2-only pipeline.
- Overall accuracy is inflated by class imbalance (94-99% OA where PV is a tiny pixel fraction). The Kappa spread is the informative figure and it swings 0.564 (mountainous Hebei, heterogeneous -- our hard case) to 0.936 (desert Qinghai). The abstract's 0.778 hides that.
- Thresholds are tuned per scene by maximizing Kappa, which undercuts the "universal, no recalibration" framing. Our test above is threshold-free (AUC), so it sidesteps this.
- The "1240x faster" claim compares DL training+inference against index calculation only, as the paper's own table note concedes.
- SPPI's user-accuracy standard deviation (±13.7%) is double MixFormer's (±6.8%).