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 regularzea.Pipeline(zea.ops.TOFCorrectionfollowed byzea.ops.DelayAndSum, chunked over grid pixels withzea.ops.PatchedGrid), so it shares its delay model (including lens correction) with the rest ofzea.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 asDASOperator, which makes the compositionDASOperator.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
|
The DAS beamformer as a differentiable linear operator. |
|
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:
objectThe 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 standardzeabeamforming pipeline:zea.ops.TOFCorrection(time-of-flight correction and receive f-number masking) followed byzea.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 roughlyn_tx * n_pix * n_el * 4 / num_patchesbytes 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 withzea.inverse.cgls().- Parameters:
parameters (zea.Parameters) – Acquisition parameters. The imaging grid is taken from
parameters.flatgrid(setxlims/zlims/grid_size_x/grid_size_zon the parameters to control it), the receive aperture fromparameters.f_number, and the lens model fromparameters.apply_lens_correction.flatgrid (Tensor, optional) – Custom pixel positions of shape
(n_pix, 3)overridingparameters.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.
- 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=2for 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.
- class zea.inverse.operators.ScattererSimulator(parameters, apply_directivity=True, chunk_size=1024, waveform_sampling_frequency=250000000.0, reference_distance=0.001)[source]¶
Bases:
objectTime-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 andDASOperatorform 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 roughlychunk_size * n_ax * n_el * 4bytes 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_wayof shape(n_tx, n_samples).apply_directivity (bool, optional) – Apply transmit/receive element directivity (requires
parameters.element_width). Defaults toTrue.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 whengeometryis 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__()viageometry=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