Skip to content

09c - Satellite pushbroom imaging simulation

LESS can connect three-dimensional surface scenes, atmospheric propagation and imaging instruments into an end-to-end link. The output is not just the ideal radiance, but can also include the detector electron count, the quantized digital value (DN), and the pixel-by-pixel observation location and time.

This function is suitable for sensor solution comparison, imaging mechanism analysis, algorithm test data generation and digital twin scene observation. The current implementation uses a local plane coordinate system to describe a segment of satellite or airborne trajectory; if the study requires complete ephemeris, attitude quaternion, earth curvature, or strict orthorectification, the observation trajectory should be generated in an external orbit tool and then connected to LESS.

Three-layer settings

A push broom imaging consists of three parts:

Hierarchy Class Function
Observation geometry Pushbroom Altitude, heading, swath, ground speed, line frequency and scan time
Spectrum and Propagation OpticalImager Band, sampling quality, atmospheric observation altitude and adjacency effect
Instrument response Instrument Aperture, integration time, transmittance, quantum efficiency, MTF, noise and ADC

Minimal example

import less

scene = less.Scene(backend="optix")
scene.size = 1000.0
scene.terrain = less.Terrain(
    property=less.Lambertian(reflectance=0.20)
)
scene.illumination = less.Illumination(
    source=less.Sun(zenith=30, azimuth=150),
    atmosphere=less.Atmosphere.standard(
        "midlatitude_summer",
        aerosol="continental",
        aot550=0.10,
        sky_mode="anisotropic",
    ),
)

projection = less.Pushbroom(
    resolution=1024,       # Number of pixels per scan line
    num_lines=2048,        # Number of scan lines along the track
    altitude=700000,       # Geometric height relative to reference surface, m
    swath_width=1000,      # Ground width, m
    heading=180,           # Counting clockwise from north
    ground_speed=7000,     # Ground speed, m/s
    line_rate=14336,       # Line frequency, line/s
    start_time=0.0,
)

instrument = less.Instrument(
    aperture_diameter=0.20,
    integration_time=0.001,
    optical_transmission=0.70,
    quantum_efficiency=0.75,
    read_noise=4.0,
    dark_current=20.0,
    full_well=80000,
    gain=5.0,              # electron / DN
    bit_depth=14,
    mtf_nyquist=0.30,
    smear=0.2,             # Smear along the track, pixel
    seed=42,
)

sensor = less.OpticalImager(
    projection=projection,
    bands=less.Sentinel2A(),
    spectral_resolution=5,
    quality=16,
    observation_level="toa",
    adjacency_sigma=1.0,   # Adjacency mixing scale, pixel
    instrument=instrument,
)

product = scene.simulate(sensor)

observation_level="toa" will automatically use scene.illumination.atmosphere to first propagate the emergent radiance of the three-dimensional scene to the top of the atmosphere and then enter the instrument chain. The user does not need to make a separate call to the atmosphere solver.

Motion and scan time

If ground_speed and line_rate are set at the same time, LESS automatically calculates the along-track coverage length based on the number of scan lines:

\[ L = v\frac{N_{line}-1}{f_{line}}. \]

You can also set ground_track_length directly. Explicit length has higher priority and is suitable when the ground coverage is already known. The time of each scan line is start_time + line / line_rate.

altitude is the relative height used in the three-dimensional ray geometry; observation_level="toa" is the end point of atmospheric propagation. The two control different physical aspects.

Instrument calculation

For each band, LESS converts the radiance into the number of photons reaching the detector, which is multiplied by the quantum efficiency to get the number of electrons. The calculation considers the effective bandwidth, entrance pupil area, pixel solid angle, integration time and optical transmittance. Then apply:

  1. PSF, MTF, jitter and track smear;
  2. Photon shot noise, dark current and readout noise;
  3. Full-well cutoff, gain, and ADC bit depth quantization.

If the band uses a spectral response function, LESS automatically calculates the equivalent bandwidth. For repeatable results, seed can be fixed; if only deterministic radiation results are to be checked, noise=False can be set.

Output product

When instrument is set, the return value is InstrumentImageProduct:

product.source_radiance  # Entrance pupil radiance after atmospheric propagation
product.radiance         # Radiance after PSF, MTF, dither and smear
product.electrons        # Detector electron number
product.dn               # ADC output; product.data is the same as it
product.geolocation      # x, y, observation zenith angle, azimuth angle and time
product.save("satellite_product.npz")  # Save all intermediate quantities
product.save("satellite_dn.tif")       # Save DN and geolocation
product.save("satellite_preview.png", bands=[3, 2, 1])

After the scene sets the projection coordinates, the per-pixel location will also include easting, northing and crs. GeoTIFF uses geographical control points to save the pushbroom geometry:

scene.georeference = {
    "crs": "EPSG:32650",
    "origin": (500000.0, 4001000.0),  # Northwest corner of the scene
}

The local coordinates of LESS are x to the east and y to the south, so the north coordinates decrease southward from the scene origin.

Adjacency effect

After setting adjacency_sigma > 0, LESS performs first-order spatial mixing of adjacent pixel radiances based on Rayleigh and aerosol scattering optical thickness along the observation path. This approximation keeps the radiance of a homogeneous scene constant and is suitable for quickly assessing adjacency effects near high-contrast boundaries. It is not a replacement model for a horizontally non-uniform three-dimensional atmosphere.

Run built-in examples

import less
product = less.examples.run(
    "satellite_pushbroom",
    show=False,
    output_dir="satellite_output",
    backend="optix",
)

OptiX, Vulkan and Embree use the same set of user interfaces. Release validation Val25 checks consistency of three-backend pushbroom radiance, as well as detector scaling, spatial response, and geolocation errors.

Current scope of application

The current version already covers pushbroom motion within a local flight segment, cross-track scanning, pixel-by-pixel perspective, one-dimensional layered atmosphere at any observation height, earth-atmosphere coupling, neighbor approximation, spectral response and detector imaging chain.

The following capabilities are not yet included: full orbital dynamics, Earth ellipsoid curvature, attitude time series, time-varying scenarios, three-dimensional radiative transfer of clouds, polarization, and adjacency effects based on strict atmospheric point spread functions. These limitations do not affect end-to-end imaging experiments under local scenes and given track conditions, but the current output should not be directly equated to geometrically processed mission-level satellite products.

  • less.Pushbroomless.OpticalImager
  • less.Instrumentless.Sentinel2A
  • less.Atmosphereless.Scene.simulate()
  • less.Product.save()less.Product.geolocation