Landsat Thermal Data Explained
On this page
Problem statement
Landsat has measured thermal infrared since 1982, which makes it the only source of surface temperature at neighbourhood resolution with a forty-year record. That record is stitched together from four generations of instruments with different resolutions, band designs and quirks, carried by satellites whose orbits have not all stayed where they started. A composite or a trend built across them inherits all of that unless it is handled explicitly.
Quick answer
| Satellite | Sensor | Thermal band | Acquired at | Level-2 asset | Notes |
|---|---|---|---|---|---|
| Landsat 5 | TM | 6 | 120 m | lwir |
1984β2012 |
| Landsat 7 | ETM+ | 6 | 60 m | lwir |
scan-line gaps from 2003; orbit drifted after 2017 |
| Landsat 8 | TIRS | 10 (11) | 100 m | lwir11 |
band 11 affected by stray light |
| Landsat 9 | TIRS-2 | 10 (11) | 100 m | lwir11 |
from 2021 |
All Collection 2 Level-2 surface temperature products are delivered resampled to 30 m, in Kelvin with scale 0.00341802 and offset 149.0.
import pandas as pd, pystac_client
cat = pystac_client.Client.open("https://planetarycomputer.microsoft.com/api/stac/v1")
rows = []
for year in (2001, 2008, 2015, 2019, 2021, 2023):
for it in cat.search(collections=["landsat-c2-l2"], bbox=[-3.72, 40.40, -3.68, 40.43],
datetime=f"{year}-06-01/{year}-08-31").items():
rows.append({"year": year, "platform": it.properties["platform"],
"utc": it.datetime.hour + it.datetime.minute / 60})
df = pd.DataFrame(rows)
table = df.groupby(["year", "platform"]).utc.agg(["count", "median"])
table["median"] = table["median"].map(lambda h: f"{int(h):02d}:{round(h % 1 * 60):02d}")
print("Summer scenes over central Madrid and their median acquisition time (UTC)")
print(table.to_string())
Summer scenes over central Madrid and their median acquisition time (UTC)
count median
year platform
2001 landsat-5 4 10:35
landsat-7 6 10:44
2008 landsat-5 2 10:42
landsat-7 4 10:45
2015 landsat-7 5 10:55
landsat-8 6 10:55
2019 landsat-7 6 10:43
landsat-8 5 10:55
2021 landsat-7 5 09:58
landsat-8 6 10:55
2023 landsat-7 9 08:43
landsat-8 6 10:55
landsat-9 6 10:55
The acquisition time of Landsat 7 moves earlier from year to year after its orbit was lowered and it drifted; Landsat 8 and 9 keep their time. Until 2019 all of them passed within a quarter of an hour of each other. In 2021 a Landsat 7 scene was taken an hour earlier than a Landsat 8 scene of the same week; by 2023, more than two hours earlier, at 08:43 UTC.
Band 10, native resolution, Landsat 7's gaps
1. Use band 10 for Landsat 8 and 9
Band 11 of TIRS suffers from stray light; the Collection 2 surface temperature product uses band 10 only, which is what the lwir11 asset contains.
2. Remember the native resolution
60 m (Landsat 7), 100 m (Landsat 8/9) or 120 m (Landsat 5), all resampled to 30 m. Features smaller than two or three native pixels are not resolved even though the file has 30 m pixels.
3. Handle Landsat 7's gaps and drift
The scan-line corrector failed in May 2003: every Landsat 7 scene since then has wedge-shaped gaps. After 2017 its orbit drifted to earlier crossing times. Mask the gaps and avoid mixing late Landsat 7 scenes with other sensors in one composite.
4. Use the right asset name per platform
lwir11 on Landsat 8/9, lwir on 5/7 in the Planetary Computer's Collection 2 items. Code that assumes one name silently skips the other satellites.
5. For long records, calibrate across sensors
Surface temperatures from TM, ETM+ and TIRS are designed to be consistent, but residual differences of a degree or so exist. Trend studies check overlaps between satellites.
Hidden resolution and scene counts by satellite
Example 1 β the resolution the pixels do not show
import numpy as np, rasterio, rasterio.warp, planetary_computer
it = next(i for i in cat.search(collections=["landsat-c2-l2"], bbox=[-3.72, 40.40, -3.68, 40.43],
datetime="2023-07-01/2023-07-31").items()
if i.properties["platform"] == "landsat-9")
with rasterio.open(planetary_computer.sign(it.assets["lwir11"].href)) as src:
xs, ys = rasterio.warp.transform("EPSG:4326", src.crs, [-3.70], [40.415])
r, c = src.index(xs[0], ys[0])
a = src.read(1, window=((r, r + 30), (c, c + 30))).astype(float) * 0.00341802 + 149 - 273.15
lag1 = np.corrcoef(a[:, :-1].ravel(), a[:, 1:].ravel())[0, 1]
lag4 = np.corrcoef(a[:, :-4].ravel(), a[:, 4:].ravel())[0, 1]
print(f"{it.id}: correlation of LST between neighbouring 30 m pixels {lag1:.2f}, "
f"pixels 120 m apart {lag4:.2f}")
LC09_L2SP_201032_20230721_02_T1: correlation of LST between neighbouring 30 m pixels 0.98, pixels 120 m apart 0.75
Neighbouring 30 m pixels correlate at 0.98 because they share most of one 100 m measurement; four pixels apart the correlation is still 0.75. They are not independent observations until well beyond the native footprint.
Example 2 β Landsat 7 scan-line gaps
l7 = next(i for i in cat.search(collections=["landsat-c2-l2"], bbox=[-3.72, 40.40, -3.68, 40.43],
datetime="2010-07-01/2010-07-31").items()
if i.properties["platform"] == "landsat-7")
with rasterio.open(planetary_computer.sign(l7.assets["lwir"].href)) as src:
xs, ys = rasterio.warp.transform("EPSG:4326", src.crs, [-3.70], [40.415])
r, c = src.index(xs[0], ys[0])
a = src.read(1, window=((r - 300, r + 300), (c - 300, c + 300)))
print(f"{l7.id}: {np.mean(a == 0):.0%} of a 18 Γ 18 km window is fill (scan-line gaps)")
LE07_L2SP_201032_20100701_02_T1: 2% of a 18 Γ 18 km window is fill (scan-line gaps)
Every post-2003 Landsat 7 scene has these gaps. Near the centre of a scene, where Madrid sits here, they are narrow β 2% of the window; they widen towards the scene edges, where they take out much more. A composite of several scenes fills them, because the gaps fall in different places each time.
Example 3 β scenes per summer by satellite
print(df.groupby(["year", "platform"]).size().unstack(fill_value=0).to_string())
platform landsat-5 landsat-7 landsat-8 landsat-9
year
2001 4 6 0 0
2008 2 4 0 0
2015 0 5 6 0
2019 0 6 5 0
2021 0 5 6 0
2023 0 9 6 6
Two satellites at a time give a scene every eight days per path; overlapping paths add more. The number of usable summer scenes β after clouds β decides how good a composite can be.
Why thermal bands are coarser
Why thermal bands are coarser
Thermal radiation carries far less energy per wavelength interval than reflected sunlight, so thermal detectors need larger pixels to collect enough signal. Landsat's thermal resolution has always been two to four times coarser than its optical bands.
Why the Level-2 product is single-band
Split-window methods use two thermal bands to correct for the atmosphere. Landsat 8's band 11 was found to be contaminated by stray light, so the Collection 2 algorithm uses band 10 with atmospheric profiles from reanalysis and emissivity from ASTER. That keeps the method consistent with the single-band Landsat 5 and 7.
Why orbit drift matters for temperature
Surface temperature rises steeply through the morning. A satellite that drifts to an earlier crossing time measures systematically cooler surfaces, so a trend built on it can show cooling that is only a change of hour.
Tiers, night scenes and uncertainty layers
- Tier 1 vs Tier 2: Tier 2 scenes have poorer geolocation; urban work should prefer Tier 1.
- Night scenes exist for some Landsat acquisitions but are rare and not in routine Level-2 processing.
- ST uncertainty: the product includes an uncertainty band (
ST_QA) in Kelvin; large values flag doubtful pixels. - Landsat Next plans more thermal bands at better resolution later in the decade.
- Harmonised composites across sensors should record which platform supplied each observation.
Internal links
- How to read Landsat surface temperature β the product in code
- LST scenes are not comparable β mixing sensors and times
- LST resolution misread β 30 m pixels, 100 m information
- Emissivity explained β the other input to the temperature
- How to build a summer LST composite β combining scenes
- Land surface temperature explained β what is being measured
FAQ
What resolution is Landsat thermal data?
Acquired at 120 m (Landsat 5), 60 m (Landsat 7) or 100 m (Landsat 8/9); delivered at 30 m.
Which band gives surface temperature on Landsat 8?
Band 10, delivered as ST_B10 (lwir11 on the Planetary Computer).
Why not use band 11?
It is affected by stray light; the official product uses band 10 only.
What happened to Landsat 7's overpass time?
Its orbit was lowered and it drifted to earlier crossing times, so late scenes are taken earlier in the morning.
Can I mix Landsat 7 and 8 in one composite?
Before about 2017 with care; afterwards, not without accounting for the time difference.
How do I handle Landsat 7's stripes?
Mask the fill pixels and composite several scenes so the gaps are filled by other dates.