zea.inverse.operators¶

Differentiable forward operators for inverse beamforming.

This module provides the two forward maps used by zea.inverse:

  • DASOperator — the delay-and-sum (DAS) beamformer as a linear operator mapping pre-beamformed channel data to a beamformed image. Built as a regular zea.Pipeline (zea.ops.TOFCorrection followed by zea.ops.DelayAndSum, chunked over grid pixels with zea.ops.PatchedGrid), so it shares its delay model (including lens correction) with the rest of zea.

  • ScattererSimulator — a time-domain point-scatterer simulator that maps scatterer positions and magnitudes to pre-beamformed channel data using the scan’s own (two-way) transmit waveforms. It uses the same delay model as DASOperator, which makes the composition DASOperator.forward(ScattererSimulator(...)) self-consistent: simulated echoes are sampled at their waveform peak by the beamformer.

Both operators are written with keras.ops and are differentiable on every Keras backend, which is what enables the optimization-based inversion in zea.inverse.inversion. Peak memory stays bounded even for scans with hundreds of transmits: the beamformer processes the imaging grid in pixel patches (zea.ops.PatchedGrid), and the simulator iterates over transmits and scatterer chunks with keras.ops.scan, rematerializing each step with keras.remat.

Classes

DASOperator(parameters[, flatgrid, ...])

The DAS beamformer as a differentiable linear operator.

ScattererSimulator(parameters[, ...])

Time-domain point-scatterer forward model producing channel data.

class zea.inverse.operators.DASOperator(parameters, flatgrid=None, fnum_window_fn=<function fnum_window_fn_tukey>, num_patches=8)[source]¶

Bases: object

The DAS beamformer as a differentiable linear operator.

Maps pre-beamformed channel data of shape (n_tx, n_ax, n_el) (or (n_tx, n_ax, n_el, n_ch)) to a flattened beamformed image of shape (n_pix,) (or (n_pix, n_ch)) with the standard zea beamforming pipeline: zea.ops.TOFCorrection (time-of-flight correction and receive f-number masking) followed by zea.ops.DelayAndSum (summation over elements and transmits). The imaging grid is processed in pixel patches (zea.ops.PatchedGrid), which bounds the peak size of the time-aligned tensor at roughly n_tx * n_pix * n_el * 4 / num_patches bytes regardless of the number of transmits.

Because the map is linear and differentiable, its adjoint (transpose) is available through adjoint(), which is all that is needed for matrix-free least-squares inversion with zea.inverse.cgls().

Parameters:
  • parameters (zea.Parameters) – Acquisition parameters. The imaging grid is taken from parameters.flatgrid (set xlims / zlims / grid_size_x / grid_size_z on the parameters to control it), the receive aperture from parameters.f_number, and the lens model from parameters.apply_lens_correction.

  • flatgrid (Tensor, optional) – Custom pixel positions of shape (n_pix, 3) overriding parameters.flatgrid.

  • fnum_window_fn (callable, optional) – Window function for the receive f-number mask. Defaults to zea.beamform.beamformer.fnum_window_fn_tukey().

  • num_patches (int, optional) – Number of grid patches processed sequentially per beamforming pass — the memory/parallelism trade-off. Defaults to 8.

__call__(channel_data)[source]¶

Alias for forward().

adjoint(image)[source]¶

Apply the adjoint (transpose) of the beamforming operator.

Computed with backend-agnostic automatic differentiation via zea.inverse.linear_adjoint(); the result is exact because the operator is linear.

Parameters:

image (Tensor) – Flattened image of shape (n_pix,).

Returns:

Channel data of shape (n_tx, n_ax, n_el).

Return type:

Tensor

forward(channel_data)[source]¶

Beamform channel data into a flattened image.

Parameters:

channel_data (Tensor) – Pre-beamformed data of shape (n_tx, n_ax, n_el) for RF or (n_tx, n_ax, n_el, n_ch) (n_ch=2 for IQ).

Returns:

Beamformed image of shape (n_pix,) when the input was 3D, else (n_pix, n_ch).

Return type:

Tensor

property input_shape¶

Shape of the channel-data input, (n_tx, n_ax, n_el).

property n_pix¶

Number of pixels in the imaging grid.

to_grid(image)[source]¶

Reshape a flattened image to the 2D imaging grid.

Parameters:

image (Tensor) – Flattened image of shape (n_pix,).

Returns:

Image of shape (grid_size_z, grid_size_x).

Return type:

Tensor

class zea.inverse.operators.ScattererSimulator(parameters, apply_directivity=True, chunk_size=1024, waveform_sampling_frequency=250000000.0, reference_distance=0.001)[source]¶

Bases: object

Time-domain point-scatterer forward model producing channel data.

Simulates pre-beamformed RF channel data of shape (n_tx, n_ax, n_el) as a superposition of point-scatterer echoes:

\[d_t(i, e) = \sum_p a_p \, c_{t,p} \, D_{rx}(p, e) \, w_t\!\left(i / f_s - \tau_{t,p,e}\right)\]

where \(\tau_{t,p,e}\) is the transmit + receive travel time computed with zea.beamform.beamformer.calculate_delays() (the same delay model as the beamformer), \(w_t\) is the scan’s two-way waveform for transmit \(t\), \(c_{t,p}\) combines spherical spreading and transmit directivity, and \(D_{rx}\) is the receive element directivity.

The travel times exclude the waveform peak offset t_peak, so a beamformer using the same parameters samples each echo exactly at its waveform peak — the simulator and DASOperator form a consistent forward model for inversion.

Scatterers are processed in chunks inside a rematerialized ops.scan (over transmits and chunks), so peak memory — also under automatic differentiation — is bounded by roughly chunk_size * n_ax * n_el * 4 bytes regardless of the total number of scatterers or transmits.

For a frequency-domain simulator with parametric pulses see zea.simulator.simulate_rf(); this class instead uses the measured waveforms stored with the scan, which matters when inverting real acquisitions.

Parameters:
  • parameters (zea.Parameters) – Acquisition parameters. Must provide waveforms_two_way of shape (n_tx, n_samples).

  • apply_directivity (bool, optional) – Apply transmit/receive element directivity (requires parameters.element_width). Defaults to True.

  • chunk_size (int, optional) – Number of scatterers processed per chunk. Defaults to 1024.

  • waveform_sampling_frequency (float, optional) – Sampling frequency of the stored waveforms in Hz. Defaults to 250e6.

  • reference_distance (float, optional) – Distance in meters at which the spherical-spreading gain is 1 (closer scatterers are clipped to 1). Defaults to 1e-3.

__call__(magnitudes, positions=None, geometry=None)[source]¶

Simulate channel data for the given scatterers.

Parameters:
  • magnitudes (Tensor) – Scatterer magnitudes of shape (n_scat,).

  • positions (Tensor, optional) – Scatterer positions of shape (n_scat, 3). Required when geometry is not given.

  • geometry (dict, optional) – Precomputed output of geometry(). Pass this when repeatedly simulating with fixed positions.

Returns:

Channel data of shape (n_tx, n_ax, n_el).

Return type:

Tensor

geometry(positions)[source]¶

Precompute the position-dependent terms of the forward model.

When solving for scatterer magnitudes with fixed positions (the linear subproblem), pass the result to __call__() via geometry= to avoid recomputing travel times on every operator application.

Parameters:

positions (Tensor) – Scatterer positions (x, y, z) of shape (n_scat, 3) in meters.

Returns:

Travel times and directivity/spreading weights.

Return type:

dict