SAR polarisation explained: VV, VH and what each responds to

On this page

Problem statement

Sentinel-1 over land delivers two images for every pass, labelled VV and VH, and most tutorials use one and ignore the other without saying why. They are not two copies of the same picture. VV — transmitted and received with vertical polarisation — responds most to surface roughness and to anything that bounces the pulse straight back. VH — transmitted vertical, received horizontal — only exists because something in the pixel has twisted the signal, which is mostly what vegetation canopies do.

The difference is large enough to separate land covers on its own. Over a scene south of Valencia, the median VV backscatter of built-up land is 5.2 dB brighter than that of cropland, while its VH is only 3.5 dB brighter; open water is the darkest class in both, by more than 10 dB.

Quick answer

Use VV for water and surface roughness, VH for vegetation volume, and their ratio for what kind of scattering dominates:

import numpy as np
from sar_io import search, passes, grid, read_pass, to_db

bbox = [-0.46, 39.25, -0.33, 39.45]
g = grid(bbox, "EPSG:25830")
frames = next(iter(passes(search(bbox, "2024-10-20/2024-10-20", orbit=110)).values()))
vv, vh = read_pass(frames, "vv", g), read_pass(frames, "vh", g)
ratio_db = to_db(vh) - to_db(vv)            # VH/VV in dB: a ratio is a difference of logs
print(f"median VV {np.nanmedian(to_db(vv)):.1f} dB, VH {np.nanmedian(to_db(vh)):.1f} dB, "
      f"VH/VV {np.nanmedian(ratio_db):.1f} dB")
median VV -9.6 dB, VH -16.7 dB, VH/VV -7.1 dB

The cross-polarised return is typically 5–8 dB weaker than the co-polarised one over land, which is why VH images look darker and noisier.

Three views of the same Sentinel-1 pass south of Valencia: VV and VH in greyscale, both showing the dark Albufera lagoon and bright towns, VH darker overall; and the VH minus VV ratio in blue and green, blue over the towns and green over the orchards and fields. Three views of the same Sentinel-1 pass south of Valencia: VV and VH in greyscale, both showing the dark Albufera lagoon and bright towns, VH darker overall; and the VH minus VV ratio in blue and green, blue over the towns and green over the orchards and fields.
The pass from the code above in both polarisations and their ratio. VV and VH agree on the water, which is dark in both, but VH is about 7 dB weaker everywhere. The ratio separates what the single bands do not: the towns and built-up strips are strongly negative (blue), because walls and ground bounce the signal back in its own polarisation; vegetated land depolarises more and comes out greener.
Surface, volume and double-bounce scattering and how each appears in VV, VH and the ratio. three scattering mechanismsmechanismVVVHVH/VVsurface (soil, water)strong if roughweaklowvolume (canopy)moderatestronghighdouble bounce (walls)very strongmoderatelowestcalm watervery weakat noise floormeaninglessBuilt-up land had the lowest ratio here (−8.5 dB): double bounce is a VV effect spatialworkflow.io
Three ways a surface returns a pulse, and the polarisation that sees each best.

VV for surfaces, VH for vegetation, the ratio for mechanism

1. Read the label as transmit–receive

The first letter is the transmitted polarisation, the second the received. Sentinel-1 over land transmits V and receives both V and H: VV is co-polarised, VH cross-polarised. Over polar ice it uses HH and HV instead.

2. Use VV for surfaces

Surface scattering — soil, water, pavement — preserves polarisation, so it appears in VV. Roughness and moisture raise VV; smooth water drops it to its lowest values.

3. Use VH for vegetation

Volume scattering among leaves, stems and branches depolarises the pulse, so a growing canopy raises VH much more than VV. That is why VH tracks crop growth and forest cover.

4. Use the ratio for mechanism

VH/VV in decibels is VH minus VV. It rises as volume scattering takes over from surface scattering, and it partly cancels effects that change both channels together, such as soil moisture and incidence angle.

5. Expect double bounce to confuse both

A wall and the ground form a corner reflector that returns strongly in VV. Buildings not aligned with the flight path also leak into VH, so urban areas can look "vegetated" in VH alone.

6. Check the noise floor

Sentinel-1's noise-equivalent sigma zero is specified at −22 dB or better. The median VH over open water here is −25.5 dB: thermal-noise removal lets values go that low, but what remains there is mostly noise, so VH is a poor channel for fine water detail.

Median VV and VH backscatter by ESA WorldCover class south of Valencia, 20 October 2024. median backscatter by land cover, 20 Oct 2024open water-20.2-25.5grassland-10-16.7cropland-9.5-16.9tree cover-9.2-15.7built-up-4.3-13.4-25 dB-20 dB-15 dB-10 dB-5 dB0 dBDark dot VV, light dot VH; the gap between them is the VH/VV ratio spatialworkflow.io
Built-up land is the brightest class in both channels; its lead over cropland is 5.2 dB in VV and 3.5 dB in VH.

Backscatter by land cover, channel by channel

The data used on this page

Sentinel-1 radiometrically terrain-corrected backscatter (sentinel-1-rtc) from the Microsoft Planetary Computer, read through sar_io.py — the small module from the reading guide that searches, groups frames into passes and mosaics each pass onto a fixed grid.

%%writefile sar_io.py
"""Find, read and mosaic Sentinel-1 RTC scenes from Microsoft Planetary Computer."""
from collections import defaultdict

import numpy as np
import planetary_computer
import pystac_client
import rasterio
from rasterio.enums import Resampling
from rasterio.transform import from_origin
from rasterio.vrt import WarpedVRT
from rasterio.warp import transform_bounds

STAC = "https://planetarycomputer.microsoft.com/api/stac/v1"


def search(bbox, dates, orbit=None, direction=None, collection="sentinel-1-rtc"):
    """Items over bbox (lon/lat) in a date range, filtered by relative orbit and pass direction."""
    cat = pystac_client.Client.open(STAC, modifier=planetary_computer.sign_inplace)
    items = cat.search(collections=[collection], bbox=bbox, datetime=dates).item_collection()
    keep = [i for i in items
            if (orbit is None or i.properties["sat:relative_orbit"] == orbit)
            and (direction is None or i.properties["sat:orbit_state"] == direction)]
    return sorted(keep, key=lambda i: i.datetime)


def passes(items):
    """Group frames into passes: same day, same relative orbit."""
    groups = defaultdict(list)
    for i in items:
        groups[(i.datetime.date(), i.properties["sat:relative_orbit"])].append(i)
    return dict(sorted(groups.items()))


def grid(bbox, crs, res=10):
    """A fixed target grid: every pass is read onto this, so arrays line up."""
    left, bottom, right, top = transform_bounds(4326, crs, *bbox)
    width, height = int((right - left) // res), int((top - bottom) // res)
    return {"crs": crs, "transform": from_origin(left, top, res, res),
            "width": width, "height": height}


def read_pass(frames, band, g):
    """Mosaic one pass's frames for one band onto grid g. Linear power; NaN where no data."""
    out = np.full((g["height"], g["width"]), np.nan, dtype="float32")
    for item in frames:
        with rasterio.open(item.assets[band].href) as src, WarpedVRT(
                src, crs=g["crs"], transform=g["transform"], width=g["width"],
                height=g["height"], resampling=Resampling.bilinear, nodata=np.nan) as vrt:
            a = vrt.read(1)
        a[a <= 0] = np.nan                       # -32768 nodata and zero-padding
        fill = np.isnan(out) & np.isfinite(a)
        out[fill] = a[fill]
    return out


def to_db(linear):
    return 10 * np.log10(linear)
Overwriting sar_io.py

Example 1 — backscatter by land cover

import pystac_client, planetary_computer, rasterio
from rasterio.enums import Resampling
from rasterio.vrt import WarpedVRT

cat = pystac_client.Client.open("https://planetarycomputer.microsoft.com/api/stac/v1",
                                modifier=planetary_computer.sign_inplace)
wc_item = next(cat.search(collections=["esa-worldcover"], bbox=bbox).items())
with rasterio.open(wc_item.assets["map"].href) as src, WarpedVRT(
        src, crs=g["crs"], transform=g["transform"], width=g["width"], height=g["height"],
        resampling=Resampling.nearest) as vrt:
    wc = vrt.read(1)

classes = {10: "tree cover", 30: "grassland", 40: "cropland", 50: "built-up", 80: "open water"}
print(f"{'class':12} {'pixels':>8} {'VV dB':>7} {'VH dB':>7} {'VH/VV':>7}")
for code, name in classes.items():
    m = (wc == code) & np.isfinite(vv) & np.isfinite(vh)
    print(f"{name:12} {m.sum():8,} {np.median(to_db(vv[m])):7.1f} "
          f"{np.median(to_db(vh[m])):7.1f} {np.median(ratio_db[m]):7.1f}")
class          pixels   VV dB   VH dB   VH/VV
tree cover    260,116    -9.2   -15.7    -6.5
grassland     506,555   -10.0   -16.7    -6.7
cropland      912,067    -9.5   -16.9    -7.3
built-up      456,725    -4.3   -13.4    -8.5
open water    267,937   -20.2   -25.5    -5.5

Example 2 — how well each channel separates two classes

def separation(a, b):
    """Difference of medians over the pooled spread: a rough signal-to-noise."""
    return abs(np.median(a) - np.median(b)) / np.std(np.concatenate([a, b]))

crop, built = (wc == 40), (wc == 50)
for name, img in [("VV", to_db(vv)), ("VH", to_db(vh)), ("VH/VV", ratio_db)]:
    ok = np.isfinite(img)
    print(f"{name:6} cropland vs built-up separation {separation(img[crop & ok], img[built & ok]):.2f}")
VV     cropland vs built-up separation 1.11
VH     cropland vs built-up separation 0.91
VH/VV  cropland vs built-up separation 0.35

For this pair VV separates best. The ratio, which cancels what the two classes have in common, barely separates them — it is a tool for telling scattering mechanisms apart, not bright from dark.

Depolarisation means volume

Why depolarisation means volume

A single reflection off a surface preserves the orientation of the electric field, give or take the surface's tilt. To rotate it from vertical to horizontal takes multiple scattering events among randomly oriented elements — which is a description of a canopy. The stronger and deeper the canopy, the more of the return arrives in the cross-polarised channel.

Why the ratio is more stable than either channel

Rain on a field raises both VV and VH, because wetter soil and leaves reflect more strongly. Their ratio moves much less, because the effect is shared. The same applies to small differences in incidence angle. That is why crop-monitoring work often uses VH/VV rather than either channel alone.

Why the numbers depend on the season

In late October the fields south of Valencia are mostly harvested rice paddies and orchards, so cropland is closer to bare surface than it would be in July. Class medians describe a date, not a land cover in general; the same code in midsummer would give cropland a higher VH and a higher ratio.

Bare surface and vegetated surface compared by what they return in VV and VH. where the ratio comes frombare or harvested fieldone bounce off the surfacepolarisation preserved → VVlittle VH: ratio lowgrowing canopymany bounces among leavespolarisation twisted → VHmore VH: ratio risesTree cover (−6.5 dB) sat above cropland (−7.3 dB) in late-October ratio spatialworkflow.io
The ratio rises as scattering moves from the surface into the canopy.

Dual-pol limits, the noise floor and seasonality

  • Dual-pol only. Sentinel-1 does not record VH and HV separately, so full polarimetric decompositions are not possible.
  • Ratio in dB is a subtraction; in linear units it is a division. Do not subtract linear values.
  • Noise floor. Over water the ratio is meaningless: VH is noise, which is why open water has the highest VH/VV of any class above (−5.5 dB).
  • Wind on water raises VV more than VH.
  • Snow and frozen ground change both channels abruptly.
  • Class medians are date-specific; compare like seasons.

FAQ

What is the difference between VV and VH?

VV is transmitted and received vertically and responds to surfaces. VH is transmitted vertically and received horizontally and responds mostly to vegetation volume.

Which polarisation is best for flood mapping?

VV. Water contrast is higher and VH is close to the noise floor over water.

Which is best for crops and forests?

VH, or the VH/VV ratio, because canopies depolarise the signal.

How do I compute the VH/VV ratio?

Subtract in decibels, or divide in linear units.

Why are cities bright in VH?

Buildings not aligned with the flight direction depolarise the return through double bounce.

Does Sentinel-1 have HH?

Only in some modes, mainly over polar regions. Over most land it records VV and VH.