Module 5: Forestry, Structure, Lidar, and Biomass
Phase: II, Core analytics
Level: Advanced
Estimated time: ~12 hours (about 5 h concepts, 6 h lab, 1 h write-up)
Prerequisites: Module 4 (features and spatial CV), Phase I, Phase 0.
Portfolio thread: completes Portfolio Project B, "Forest structure and carbon loss," with canopy-height and above-ground biomass maps that carry real uncertainty.
Why this module
Carbon and forestry companies (Pachama, Sylvera, Chloris, CTrees, and Planet's forest teams) hire on exactly this skill: fusing sparse lidar footprints with wall-to-wall imagery to map canopy height and above-ground biomass density, with defensible uncertainty. The differentiator is not producing a pretty height map; it is attaching honest prediction intervals and validating against independent references, because a biomass number without an uncertainty is not usable for a carbon audit. This module also puts you on the frontier: GEDI is collecting again, and ESA's Biomass P-band mission is now live, so you can speak to the newest data in the field.
Learning outcomes
After this module you can:
- Explain GEDI (L2A relative-height metrics, L4A footprint biomass, L4B gridded) and ICESat-2 ATL08 canopy products, and filter them by quality.
- Explain why C-band saturates over dense forest and what L-band and P-band add, and where the new Biomass mission fits.
- Fuse lidar footprints with imagery features to map canopy height and AGBD wall to wall.
- Attach prediction intervals with quantile regression and conformal prediction, and validate against independent biomass references.
- Combine forest-loss alerts (RADD, GLAD) with your maps to estimate biomass lost per year.
- Ship maps with uncertainty rasters and an honest validation notebook.
Concept lessons (about 5 hours)
Lesson 1: Spaceborne lidar, GEDI and ICESat-2
Lidar measures 3D structure directly by timing laser returns. Two spaceborne sources matter:
- GEDI is a full-waveform lidar on the International Space Station. Its products build on each other: L2A gives relative-height metrics per footprint (RH50, RH98, and so on, describing the canopy profile), L4A gives above-ground biomass density per footprint from those metrics, and L4B gives gridded biomass. GEDI samples in footprints along orbit tracks, not wall to wall, so it is training and reference data, not a finished map. Note the coverage gap: GEDI paused in March 2023 and resumed science operations in June 2024, so there is a hole in the record you must account for in any time series.
- ICESat-2 ATL08 provides canopy and terrain heights from a photon-counting lidar, a different measurement principle from GEDI's waveforms, useful especially at higher latitudes GEDI does not reach.
Both need quality filtering: use the quality and degrade flags and a sensitivity threshold, and be aware of beam type (power versus coverage beams) and geolocation uncertainty.
Lesson 2: Why radar band matters for biomass
As Module 3 covered, C-band (Sentinel-1) saturates over dense forest: above moderate biomass it stops responding, so it cannot separate a heavy forest from a very heavy one. Longer wavelengths penetrate deeper into the canopy and woody structure:
- L-band (ALOS-2, and NISAR in Module 9) sees branches and trunks and holds signal to higher biomass.
- P-band is the longest and penetrates to the woody biomass that stores most carbon. This is exactly why ESA built the Biomass mission, which is now operational and delivering open data, the first spaceborne P-band SAR. It is designed to map forest biomass and its change where optical and C-band cannot, and it belongs in your mental toolkit as the new frontier reference for carbon.
Lesson 3: Fusing lidar with imagery
The standard approach to a wall-to-wall product: use GEDI (or ICESat-2) footprints as the target (canopy height or AGBD), and the Module 4 feature stack (optical composites and indices, Sentinel-1 backscatter and ratio, terrain) as predictors, then train a regressor and predict everywhere. The current literature (for example global canopy-height models fusing GEDI with Sentinel-2, and very-high-resolution canopy-height models from commercial imagery) all follow this footprints-plus-imagery pattern; you are building a scoped version of the same idea. Carry the spatial cross-validation discipline from Module 4, because height and biomass are strongly autocorrelated and random splits will flatter you badly here.
Lesson 4: Uncertainty done properly
A biomass map without uncertainty is not fit for carbon accounting. Two complementary tools:
- Quantile regression trains the model to predict conditional quantiles (for example the 5th and 95th percentiles), giving a native prediction interval that can vary across the map.
- Conformal prediction wraps any model with a calibration step on held-out residuals to produce intervals with a guaranteed average coverage level, distribution-free. Split conformal is simple and strong: reserve a calibration set, take the appropriate quantile of absolute residuals, and use it as the interval half-width. This is the current best practice for trustworthy intervals.
Validate against independent references (CCI Biomass, GEDI L4B gridded, and increasingly the Biomass mission's products), and report error the same honest way as earlier modules: held out, with intervals, no leakage. In a real carbon project this connects to MRV standards and their allometry and uncertainty requirements.
Lesson 5: From maps to carbon loss
Overlay forest-disturbance alerts (RADD and GLAD, which flag likely loss from radar and optical) and the Hansen year-of-loss layer on your biomass map to estimate biomass, and therefore carbon, lost per year in the AOI. This turns a static map into a change story, which is what buyers actually want.
Guided lab (about 6 hours): canopy height and biomass with intervals
Step 1: Pull and filter GEDI
Over your tropical AOI, pull GEDI L2A (RH metrics) and L4A (footprint AGBD) via NASA Earthdata (the earthaccess package). Filter for quality and sensitivity and keep good beams.
"""forestry.py: lidar filtering and conformal prediction intervals."""
from __future__ import annotations
import numpy as np
def gedi_quality_filter(df, min_sensitivity=0.95):
"""Keep only high-quality GEDI shots (expects quality_flag, degrade_flag, sensitivity)."""
return df[(df["quality_flag"] == 1) &
(df["degrade_flag"] == 0) &
(df["sensitivity"] >= min_sensitivity)]
def conformal_halfwidth(cal_residuals, alpha=0.1):
"""Split-conformal interval half-width for coverage 1 - alpha (distribution-free).
Reserve a calibration set, pass its absolute residuals, get the half-width to add
and subtract from predictions for approx (1 - alpha) coverage.
"""
r = np.abs(np.asarray(cal_residuals, float))
n = len(r)
level = min(1.0, np.ceil((n + 1) * (1 - alpha)) / n)
return float(np.quantile(r, level, method="higher"))
# tests/test_forestry.py
import numpy as np, pandas as pd
from eo_portfolio.forestry import gedi_quality_filter, conformal_halfwidth
def test_quality_filter():
df = pd.DataFrame({"quality_flag":[1,1,0], "degrade_flag":[0,1,0], "sensitivity":[0.98,0.99,0.99]})
out = gedi_quality_filter(df)
assert len(out) == 1 and out.iloc[0]["sensitivity"] == 0.98
def test_conformal_halfwidth_and_monotonicity():
assert conformal_halfwidth(list(range(1, 11)), alpha=0.1) == 10.0
r = list(range(1, 101))
assert conformal_halfwidth(r, 0.05) >= conformal_halfwidth(r, 0.2)
Step 2: Train a canopy-height model
Using the Module 4 feature stack as predictors and GEDI RH98 as the target, train a gradient-boosted regressor (or quantile regressor). Evaluate with spatial block cross-validation. Predict wall to wall and write the height map as a COG.
Step 3: Add intervals and an AGBD map
Reserve a calibration split and compute conformal_halfwidth on its residuals to produce a prediction-interval raster, or train quantile models for a spatially varying interval. Repeat the modeling for above-ground biomass (GEDI L4A target). Compare your AGBD map against CCI Biomass and GEDI L4B at 1 km, and, if available, the Biomass mission products.
Step 4: Carbon loss over time
Overlay RADD and GLAD alerts and the Hansen year-of-loss layer, and compute biomass lost per year across the AOI, with uncertainty propagated from your interval raster.
Step 5: Write-up and commit
A validation notebook and a short results piece: "Forest structure and carbon loss, AOI X, 2019 to 2025," with the height and AGBD maps, their uncertainty rasters, the validation against references, and the annual biomass-loss estimate. Commit forestry.py, tests, and the notebook.
git add src/eo_portfolio/forestry.py tests/test_forestry.py notebooks/07_forest_biomass.ipynb
git commit -m "Module 5: canopy height + AGBD with conformal intervals and carbon loss"
git push
Checkpoint
Self-check (answers below).
- Why is GEDI training and reference data rather than a finished wall-to-wall map?
- Why does C-band saturate over dense forest, and what do L-band and P-band add?
- What guarantee does split conformal prediction give, and how do you compute the interval?
- You are building a GEDI-derived time series across 2022 to 2025. What data issue must you handle?
Interview-style questions (practice out loud).
- How would you fuse GEDI with wall-to-wall imagery to map canopy height, and how would you validate it?
- How do you estimate uncertainty on a biomass map at project scale for an MRV audit?
- When would you choose the Biomass mission or an L-band sensor over Sentinel-1 for a carbon task?
- Your height map's random-split error looks great but field checks are poor. What likely went wrong?
Answers. (1) GEDI samples in footprints along orbit tracks, not continuously, so it provides point targets and validation, and you need imagery to interpolate between tracks.
(2) C-band's short wavelength interacts with the upper canopy and stops responding above moderate biomass; L-band penetrates to branches and trunks and P-band to woody biomass, extending sensitivity to the high-biomass range where carbon is stored.
(3) It gives approximately (1 minus alpha) average coverage, distribution-free; reserve a calibration set, take the (1 minus alpha) quantile of absolute residuals (finite-sample adjusted), and use it as the interval half-width.
(4) The GEDI coverage gap from March 2023 to April 2024, during which no data were collected, so the series has a hole you must not interpolate over silently.
Deliverable
A tested forestry.py (GEDI quality filter, conformal intervals), a notebooks/07_forest_biomass.ipynb producing canopy-height and AGBD maps with uncertainty rasters, validated against CCI Biomass and GEDI L4B, plus an annual biomass-loss estimate over the AOI. This completes Portfolio Project B.
What a hiring manager sees
Carbon teams see a lot of height maps and very few with honest, calibrated uncertainty. Showing that you filter lidar by quality, fuse it with imagery under spatial cross-validation, attach conformal or quantile intervals, and validate against independent references is exactly their hiring bar. Referencing the current data landscape correctly (GEDI's gap, the live Biomass mission) signals you track the field, which carbon-MRV employers value.
Currency note
Verified August 2026. GEDI resumed science operations on 11 June 2024 after a hibernation from 17 March 2023 to 24 April 2024 (no data in that window) and aims to operate toward 2030; account for the gap in any time series. GEDI L2A, L4A, and L4B are distributed via NASA Earthdata (LP DAAC and ORNL DAAC), accessible with earthaccess. ESA's Biomass P-band mission completed commissioning on 26 January 2026 and is in full science operations with open data now available; its higher-level biomass products are rolling out, so check current availability. CCI Biomass is updated periodically, so use the latest version, and confirm RADD and GLAD alert coverage for your AOI. Conformal prediction tooling (for example MAPIE) and quantile regressors are stable; pin versions in your Module 0.1 environment file.