torchbp.util module

torchbp.util.argmax_nd(x)[source]

torch.argmax but returns N-dimensional index of the peak

Parameters:

x (Tensor)

Return type:

tuple[int, …]

torchbp.util.bounding_cart_grid(grid_polar, origin, origin_angle)[source]

Return the bounding Cartesian grid for polar input grid.

Parameters:
  • grid_polar (PolarGrid or dict) –

    Polar grid definition. Can be:

    • PolarGrid object: PolarGrid(r_range=(r0, r1), theta_range=(theta0, theta1), nr=nr, ntheta=ntheta)

    • dict: {“r”: (r0, r1), “theta”: (theta0, theta1), “nr”: nr, “ntheta”: ntheta}

    where theta is sin of angle (-1, 1 for 180 degree view).

  • origin (tuple) – Origin coordinates of grid_polar in the Cartesian grid.

  • origin_angle (float) – Reference direction (radians) that corresponds to s = 0.

Returns:

(xmin, ymin, xmax, ymax) – Coordinates of the smallest axis‑aligned rectangle containing the grid.

Return type:

tuple[float, float, float, float]

torchbp.util.bp_polar_range_alias(img, origin, fc, grid_polar, alias_fmod=0, dem=None)[source]

Inverse of bp_polar_range_dealias.

Parameters:
  • img (Tensor) – Complex input image. Shape should be: [Range, azimuth] or [nbatch, Range, azimuth].

  • origin (Tensor) – Center of the platform position.

  • fc (float) – RF center frequency.

  • grid_polar (PolarGrid or dict) –

    Polar grid definition. Can be:

    • PolarGrid object: PolarGrid(r_range=(r0, r1), theta_range=(theta0, theta1), nr=nr, ntheta=ntheta)

    • dict: {“r”: (r0, r1), “theta”: (theta0, theta1), “nr”: nr, “ntheta”: ntheta}

  • alias_fmod (float) – Range modulation frequency applied to output.

  • dem (Tensor or None) – Digital elevation model sampled on the image polar grid. See bp_polar_range_dealias(). Must be the same dem the image was dealiased with.

Returns:

img – SAR image with range spectrum aliasing.

Return type:

Tensor

torchbp.util.bp_polar_range_dealias(img, origin, fc, grid_polar, alias_fmod=0, dem=None)[source]

De-alias range-axis spectrum of polar SAR image processed with backprojection. [1]

Equivalent to the dealias option of torchbp.ops.backprojection_polar_2d() when origin is the center of the platform positions used for backprojection ([0, 0, z0] when the positions were centered) and the same dem is given.

Parameters:
  • img (Tensor) – Complex input image. Shape should be: [Range, azimuth] or [nbatch, Range, azimuth].

  • origin (Tensor) – Center of the platform position.

  • fc (float) – RF center frequency.

  • grid_polar (PolarGrid or dict) –

    Polar grid definition. Can be:

    • PolarGrid object: PolarGrid(r_range=(r0, r1), theta_range=(theta0, theta1), nr=nr, ntheta=ntheta)

    • dict: {“r”: (r0, r1), “theta”: (theta0, theta1), “nr”: nr, “ntheta”: ntheta}

  • alias_fmod (float) – Range modulation frequency applied to input.

  • dem (Tensor or None) – Digital elevation model sampled on the image polar grid, same convention as the dem input of torchbp.ops.backprojection_polar_2d(): float32 [dem_nr, dem_ntheta] covering the grid extent, can be coarser than the image grid (bilinearly interpolated). When given, the carrier is referenced to the pixel at the DEM height, matching the dealias carrier of a backprojection with the same dem. If None the carrier is referenced to the z=0 plane.

Return type:

Tensor

References

[1]

T. Shi, X. Mao, A. Jakobsson and Y. Liu, “Extended PGA for Spotlight SAR-Filtered Backprojection Imagery,” in IEEE Geoscience and Remote Sensing Letters, vol. 19, pp. 1-5, 2022, Art no. 4516005.

Returns:

img – SAR image without range spectrum aliasing.

Return type:

Tensor

Parameters:
  • img (Tensor)

  • origin (Tensor)

  • fc (float)

  • grid_polar (PolarGrid | dict)

  • alias_fmod (float)

  • dem (Tensor | None)

torchbp.util.center_pos(pos)[source]

Center position to origin. Centers X and Y coordinates, but doesn’t modify Z. Useful for preparing positions for polar backprojection

Parameters:

pos (Tensor) – 3D positions. Shape should be [N, 3].

Returns:

  • pos_local (Tensor) – Centered positions.

  • origin (Tensor) – Position subtracted from the pos.

Return type:

tuple[Tensor, Tensor]

torchbp.util.contrast(x, dim=-1)[source]

Calculates negative contrast:

-mean(std/mu)

where mu is mean and std is standard deviation of abs(x) along dimension dim.

Parameters:
  • x (Tensor) – Input tensor.

  • dim (int)

Returns:

contrast – Calculated negative contrast of the input.

Return type:

Tensor

torchbp.util.conv_lowpass_filter(data, window_width)[source]

Time-domain lowpass filter: moving average with Hamming window taps along the last axis, with replicate edge padding.

Time-domain alternative to fft_lowpass_filter_window(). Note the different parameter meaning: window_width is the filter length in samples (cutoff at roughly 1 / window_width cycles per sample), while the FFT variant’s width is in frequency bins. Replicate padding avoids the edge roll-off that zero padding causes on short signals. Works for real and complex input.

Parameters:
  • data (Tensor) – Input tensor, filtered along the last axis.

  • window_width (int) – Filter length in samples. Lengths <= 1 (or longer than the signal) return the input unchanged.

Returns:

filtered_data – Filtered tensor with the same shape as the input.

Return type:

Tensor

torchbp.util.create_triangular_weights(patch_size, overlap, device='cpu')[source]

Create triangular weights for smooth blending of overlapping patches.

Parameters:
  • patch_size (int) – Side length of patches.

  • overlap (int) – Overlap between patches.

  • device (str) – Pytorch device.

Returns:

weights_2d – Weight tensor of [patch_size, patch_size] with triangular weighting

Return type:

Tensor

torchbp.util.dem_to_polar(dem, dem_grid, polar_grid, origin=None, rotation=0.0)[source]

Resample a Cartesian DEM onto a polar grid for use as the dem input of torchbp.ops.backprojection_polar_2d.

Parameters:
  • dem (Tensor) – Cartesian DEM heights, shape [nx, ny] on dem_grid. Same x/y coordinate frame and z datum as the platform positions before subtracting origin.

  • dem_grid (CartesianGrid or dict) – Cartesian grid of dem.

  • polar_grid (PolarGrid or dict) – Polar grid to sample to. Should have the same r and theta extent as the imaging grid; nr and ntheta can be smaller for a downsampled DEM.

  • origin (Tensor or None) – Polar grid origin [x, y, z] in the DEM frame (the origin subtracted from the platform positions). Default is zeros.

  • rotation (float) – Polar grid rotation in radians, same convention as torchbp.ops.polar_to_cart.

Returns:

dem_polar – DEM heights at the polar grid points relative to the origin z, shape [nr, ntheta] float32. Points outside the DEM extent take the nearest border value. Guard band points |theta| > 1 sample at the clamped angle.

Return type:

Tensor

torchbp.util.detrend(x)[source]

Removes linear trend

Parameters:

x (Tensor) – Input tensor. Should be 1 dimensional.

Returns:

x – x with linear trend removed.

Return type:

Tensor

torchbp.util.diff(x, dim=-1, same_size=False)[source]

np.diff implemented in torch.

Parameters:
  • x (Tensor) – Input tensor.

  • dim (int) – Dimension.

  • same_size (bool) – Pad output to same size as input.

Returns:

d – Difference tensor.

Return type:

Tensor

torchbp.util.entropy(x)[source]

Calculates entropy:

-sum(y*log(y))

where y = abs(x) / sum(abs(x)).

Parameters:

x (Tensor) – Input tensor.

Returns:

entropy – Calculated entropy of the input.

Return type:

Tensor

torchbp.util.extract_overlapping_patches(img, patch_size, overlap)[source]

Extract overlapping patches from a tensor.

Parameters:
  • img (Tensor) – Input tensor of shape [C, N, M].

  • patch_size (int) – Side length of square patches (K).

  • overlap (int) – Overlap between patches.

Returns:

  • patches (Tensor) – Tensor of shape [C, P, K, K] where P is the number of patches.

  • dim (tuple) – Original image dimensions.

Return type:

tuple[Tensor, tuple[int, …]]

torchbp.util.fft_lowpass_filter_precalculate_window(data_length, window_width, device, window, circular_conv=False, fast_len=True)[source]

Precompute window to be used with fft_lowpass_filter_window.

Returns:

w – Windowing Tensor.

Return type:

Tensor

Parameters:
  • data_length (int)

  • window_width (int)

  • device (str)

  • window (str | tuple)

  • circular_conv (bool)

  • fast_len (bool)

torchbp.util.fft_lowpass_filter_window(target_data, window='hamming', window_width=None, circular_conv=False, fast_len=True)[source]

FFT low-pass filtering with a configurable window function.

Parameters:
  • target_data (Tensor)

  • window (str | tuple | Tensor)

  • window_width (int)

  • circular_conv (bool)

  • fast_len (bool)

Return type:

Tensor

torchbp.util.fft_peak_1d(x, dim=-1, fractional=True)[source]

Find fractional peak of abs(fft(x)).

Parameters:
  • x (Tensor) – Input tensor.

  • dim (int) – Dimension to calculate peak.

  • fractional (bool) – Estimate peak location with fractional index accuracy.

Returns:

a – Estimated peak index.

Return type:

int or float

torchbp.util.find_image_shift_1d(x, y, dim=-1)[source]

Find shift between images that maximizes correlation.

Parameters:
  • x (Tensor) – Input tensor.

  • y (Tensor) – Input tensor. Should have same shape as x.

  • dim (int) – Dimensions to shift.

Returns:

c – Estimated shift.

Return type:

Tensor

torchbp.util.find_image_shift_2d(x, y, dim=(-2, -1), interpolate=False)[source]

Find shift between images that maximizes correlation.

Parameters:
  • x (Tensor) – Input tensor.

  • y (int) – Input tensor. Should have same shape as x.

  • dim (tuple) – Dimension.

Returns:

  • c (tuple) – Estimated shift.

  • a (float) – Peak of correlation.

Return type:

tuple

torchbp.util.generate_fmcw_data(target_pos, target_rcs, pos, fc, bw, tsweep, fs, d0=0, g=None, g_extent=None, att=None, rvp=True, vel=None)[source]

Generate FMCW radar time-domain IF signal.

Parameters:
  • target_pos (Tensor) – [ntargets, 3] tensor of target XYZ positions.

  • target_rcs (Tensor) – [ntargets, 1] tensor of complex target reflectivity, used directly as the signal amplitude (same convention as the image input of torchbp.ops.projection_cart_2d).

  • pos (Tensor) – [nsweeps, 3] tensor of platform positions. When vel is provided, pos[s] is the platform position at the midpoint of sweep s.

  • fc (float) – RF center frequency in Hz.

  • bw (float) – RF bandwidth in Hz.

  • tsweep (float) – Length of one sweep in seconds.

  • fs (float) – Sampling frequency in Hz.

  • d0 (float) – Zero range.

  • g (Tensor or None) – Square-root of two-way antenna gain in spherical coordinates, shape: [elevation, azimuth]. If TX antenna equals RX antenna, then this should be just antenna gain. (0, 0) angle is at the beam center. Isotropic antenna is assumed if g is None.

  • g_extent (list or None) – List of [g_el0, g_az0, g_el1, g_az1]. g_el0, g_el1 are grx and gtx elevation axis start and end values. Units in radians. -pi/2 + +pi/2 if including data over the whole sphere. g_az0, g_az1 are grx and gtx azimuth axis start and end values. Units in radians. -pi to +pi if including data over the whole sphere.

  • att (Tensor) – Euler angles of the radar antenna at each data point. Shape should be [nsweeps, 3]. [Roll, pitch, yaw]. Only roll and yaw are used at the moment.

  • rvp (bool) – True to include residual video phase term.

  • vel (Tensor or None) – [nsweeps, 3] tensor of platform velocities in m/s. When given, the two-way delay is evaluated per intra-sweep sample at the instantaneous platform position pos[s] + vel[s] * (t_sample - tsweep/2), i.e. the stop-and-go approximation is removed. None (default) reproduces the stop-and-go model where pos[s] is held fixed across the chirp.

Returns:

data – [nsweeps, nsamples] measurement data.

Return type:

Tensor

torchbp.util.make_polar_grid(r0, r1, nr, ntheta, theta_limit=1, squint=0)[source]

Generate PolarGrid object.

Parameters:
  • r0 (float) – Minimum range in m.

  • r1 (float) – Maximum range in m.

  • nr (float) – Number of range points.

  • ntheta (float) – Number of azimuth points.

  • theta_limit (float) – Theta axis limits, symmetrical around zero. Units are sin of angle (0 to 1 valid range). Default is 1.

  • squint (float) – Grid azimuth mean angle, radians.

Returns:

grid_polar – Polar grid object.

Return type:

PolarGrid

torchbp.util.make_polar_grid_obj(r0, r1, nr, ntheta, theta_limit=1, squint=0)

Generate PolarGrid object.

Parameters:
  • r0 (float) – Minimum range in m.

  • r1 (float) – Maximum range in m.

  • nr (float) – Number of range points.

  • ntheta (float) – Number of azimuth points.

  • theta_limit (float) – Theta axis limits, symmetrical around zero. Units are sin of angle (0 to 1 valid range). Default is 1.

  • squint (float) – Grid azimuth mean angle, radians.

Returns:

grid_polar – Polar grid object.

Return type:

PolarGrid

torchbp.util.merge_patches_with_triangular_weights(patches, original_shape, patch_size, overlap, padded_shape=None)[source]

Merge overlapping patches back into an image using triangular weighting.

Parameters:
  • patches (Tensor) – Tensor of shape [C, P, K, K] containing patches

  • original_shape (tuple) – Original shape of the image (N, M).

  • patch_size (int) – Side length of square patches (K).

  • overlap (int) – Overlap between patches.

  • padded_shape (tuple) – Tuple (N_pad, M_pad) of padded dimensions.

Returns:

img – Reconstructed image tensor of shape [C, N, M].

Return type:

Tensor

torchbp.util.next_fast_len(n)[source]

CuFFT-friendly length (powers of 2,3,5,7)

Parameters:

n (int)

Return type:

int

torchbp.util.phase_to_distance(p, fc)[source]

Convert radar reflection phase shift to distance.

Parameters:
  • p (Tensor) – Phase shift tensor.

  • fc (float) – RF center frequency.

Return type:

Tensor

torchbp.util.polar_dem_slopes(dem, grid, theta_psi=False)[source]

Stack a polar-grid DEM with its Cartesian terrain slopes for the dem input of the tx_power kernels.

Parameters:
  • dem (Tensor) – DEM heights on the polar grid, shape [dem_nr, dem_ntheta]. Covers the same r and theta extent as grid; the resolution can differ.

  • grid (PolarGrid or dict) – Polar grid giving the r and theta extents (nr and ntheta are taken from dem).

  • theta_psi (bool) – If True the theta axis is uniform in the angle psi (radians) instead of sin(psi). Used for the ffbp subaperture node grids.

Returns:

dem3 – [3, dem_nr, dem_ntheta] float32 stack (z, dz/dx, dz/dy). The slopes are in the Cartesian frame of the grid origin and are translation invariant, so the same values apply in shifted subaperture frames.

Return type:

Tensor

torchbp.util.process_image_with_patches(img, patch_size, overlap, process_fn)[source]

Process an image by extracting patches, applying a function, and merging back.

Parameters:
  • img (Tensor) – Input tensor of shape [C, N, M] or [N, M].

  • patch_size (int) – Side length of square patches.

  • overlap (int) – Overlap between patches.

  • process_fn (function) – Function to apply to patches.

Returns:

img – Processed image with same shape as the input.

Return type:

Tensor

torchbp.util.quad_interp(a, v)[source]

Quadractic peak interpolation. Useful for FFT peak interpolation.

Parameters:
  • a (Tensor) – Input tensor.

  • v (int) – Peak index.

Returns:

f – Estimated fractional peak index.

Return type:

Tensor

torchbp.util.shift_spectrum(x, dim=-1)[source]

Equivalent to: fft(ifftshift(ifft(x, dim), dim), dim), but avoids calculating FFTs.

Parameters:
  • x (Tensor) – Input tensor.

  • dim (int)

Returns:

y – Shifted tensor.

Return type:

Tensor

torchbp.util.subset_cart(img, grid_cart, x0, x1, y0, y1)[source]

Cartesian image subset.

Parameters:
  • img (Tensor) – Input image.

  • grid_cart (CartesianGrid or dict) –

    Cartesian grid definition. Can be:

    • CartesianGrid object: CartesianGrid(x_range=(x0, x1), y_range=(y0, y1), nx=nx, ny=ny)

    • dict: {“x”: (x0, x1), “y”: (y0, y1), “nx”: nx, “ny”: ny}

  • x0 (float) – Subset x0.

  • x1 (float) – Subset x1.

  • y0 (float) – Subset y0.

  • y1 (float) – Subset y1.

Returns:

  • img (Tensor) – Subset of input image.

  • grid (dict) – Grid

Return type:

tuple[Tensor, dict]

torchbp.util.subset_polar(img, grid_polar, r0, r1, theta0, theta1)[source]

Polar image subset.

Parameters:
  • img (Tensor) – Input image.

  • grid_polar (PolarGrid or dict) – Polar grid definition. PolarGrid object or dictionary.

  • r0 (float) – Subset r0.

  • r1 (float) – Subset r1.

  • theta0 (float) – Subset theta0.

  • theta1 (float) – Subset theta1.

Returns:

  • img (Tensor) – Subset of input image.

  • grid_new (dict) – Grid.

Return type:

tuple[Tensor, dict]

torchbp.util.taper_antenna_pattern(g, g_extent, az_margin, el_margin=0.0)[source]

Extend an antenna gain pattern with a raised-cosine roll-off to zero.

The backprojection kernels treat angles outside the pattern table as exactly zero gain, so a measured pattern that ends at its measurement extent with nonzero gain has a hard cutoff step there. When the table edge falls inside the scene, the step degrades algorithms that model the gain envelope as smooth: the torchbp.ops.afbp() wavenumber fusion with per-pulse gain cannot represent the step (the accumulation dims and smears around the cutoff), and with platform yaw the step sweeps over the edge pixels, which also degrades the frozen-gain antenna_leaf_gain="subaperture" model of torchbp.ops.ffbp(). Rolling the edge value off to zero over a margin removes the step; the taper region slightly underweights pixels there, consistently in both the accumulation and the illumination maps.

Parameters:
  • g (Tensor) – Antenna gain pattern, shape [g_nel, g_naz].

  • g_extent (list) – Pattern extent [g_el0, g_az0, g_el1, g_az1] in radians.

  • az_margin (float) – Azimuth roll-off width in radians, added on both sides. Rounded to whole table cells; 0 disables.

  • el_margin (float) – Same for the elevation axis. Default 0.

Returns:

(g, g_extent) – Extended pattern and its extent, same cell size as the input.

Return type:

tuple[Tensor, list]

torchbp.util.unwrap(phi, dim=-1)[source]

np.unwrap implemented in torch.

Parameters:
  • phi (Tensor) – Input tensor.

  • dim (int) – Dimension.

Returns:

phi – Unwrapped tensor.

Return type:

Tensor

torchbp.util.unwrap_ref(x, y)[source]

Solve for integer array k such that x + k*2pi is closest to y. k = round((y - x) / (2pi)).

Parameters:
  • x (Tensor) – Phase wrapped signal.

  • y (Tensor) – Reference signal.

Returns:

unwrapped_x – Phase unwrapped x

Return type:

Tensor

torchbp.util.weighted_detrend(x, w)[source]

Removes weighted linear trend.

The removed line is the weighted least squares fit, so samples with zero weight do not affect the fit but the line is still subtracted over the whole tensor. Degenerate weights (all zero or concentrated on one sample) remove only the weighted mean.

Parameters:
  • x (Tensor) – Input tensor. Should be 1 dimensional.

  • w (Tensor or None) – Non-negative per-sample weights with the same shape as x. None falls back to the unweighted detrend().

Returns:

x – x with weighted linear trend removed.

Return type:

Tensor

torchbp.util.wiener_normalize(sar, tx_power, eps=None, calib_quantile=0.1)[source]

SNR-aware radiometric normalization of a SAR image by an illumination map.

Plain division sar / tx_power inverts the illumination, but where the illumination is weak (swath edges, antenna nulls) it divides receiver noise by a near-zero number and the result blows up. This applies the Wiener (MMSE) estimate instead:

\[\hat{s} = \frac{\mathrm{sar}\cdot\mathrm{tx\_power}} {\mathrm{tx\_power}^2 + \varepsilon^2}\]

which equals (sar / tx_power) * SNR / (1 + SNR) with the per-pixel power SNR = (tx_power / eps)**2. Where the illumination is strong it reduces to the full normalization sar / tx_power; where it is weak the gain rolls off as tx_power**2 so the output goes to zero instead of amplifying noise. The SNR map itself is (tx_power / eps)**2.

The regularization eps is the noise-to-signal amplitude ratio \(\varepsilon = \sigma_n / \sigma_s\) in tx_power units, where \(\sigma_n\) is the additive noise amplitude in the image and \(\sigma_s\) is the reflectivity scale relating image to illumination (sar = s * tx_power + n). It is the illumination level at which the SNR equals one. Note this is not simply the noise level \(\sigma_n\): it must be divided by the reflectivity scale (which also absorbs the leftover radiometric calibration constant of tx_power).

Parameters:
  • sar (Tensor) – Complex or magnitude SAR image. 2D (nr, ntheta) or 3D (nbatch, nr, ntheta).

  • tx_power (Tensor) – Illumination map from torchbp.ops.backprojection_polar_2d_tx_power() (square root of power returned for unit reflectivity), real-valued with the same number of dimensions as sar. Its trailing two dimensions may be coarser than sar; if so it is bilinearly interpolated up to sar’s grid on the fly (via torchbp.ops.mul_2d_interp_linear() / torchbp.ops.div_2d_interp_linear()) so no full-resolution map is allocated. Non-finite entries (un-illuminated pixels) are treated as no-data and mapped to zero.

  • eps (float or None) – Regularization level \(\sigma_n / \sigma_s\) in tx_power units. If None it is estimated from the data using the identity \(E|\mathrm{sar}|^2 = \sigma_s^2\,\mathrm{tx\_power}^2 + \sigma_n^2\): \(\sigma_s^2\) from the brightest calib_quantile fraction of pixels and \(\sigma_n^2\) from the dimmest fraction (with the residual signal subtracted). For real data prefer passing an explicit value from a known shadow region and a calibration target.

  • calib_quantile (float) – Fraction (0-0.5) of pixels at each illumination extreme used to estimate eps when it is not given. Default 0.1 (dimmest/brightest 10%).

Returns:

s_hat – Normalized image, same dtype as sar.

Return type:

Tensor