zea.beamform.geometry¶

Geometry helpers for beamforming.

Lightweight, backend-agnostic utilities derived purely from probe and transmit geometry. This is a leaf module (only depends on keras / numpy) so it can be imported from zea.beamform.beamformer, zea.simulator and zea.beamform.pfield without introducing an import cycle.

The transmit helpers (transmit_apex_distance(), insonified_edge_rays()) work in the x-z imaging plane and in zea’s transducer frame: z = 0 at the middle of the array, +z into the medium, and angles measured from +z, positive toward +x. They back the default beamforming grid of zea.Parameters.

Module Attributes

STEERING_TOLERANCE

Polar angles at or below this magnitude [rad] count as unsteered.

SINC_HALF_AMPLITUDE

The argument x at which sinc(x) = sin(pi x) / (pi x) drops to 0.5 (-6 dB).

Functions

compute_element_normals(probe_geometry[, eps])

Estimate per-element unit surface normals from element positions.

element_acceptance_angle(element_width, ...)

Half-angle within which a single element receives, at -6 dB.

element_pitch(probe_geometry)

Median distance between neighbouring elements in metres.

insonified_edge_rays(probe_geometry, ...[, ...])

Edge rays bounding the region each transmit insonifies, in the x-z plane.

is_diverging(focus_distances)

Mask of the transmits that are diverging waves.

is_focused(focus_distances)

Mask of the transmits that are focused.

is_plane_wave(focus_distances)

Mask of the transmits that are plane waves.

rays_at_depth(points, directions, depth)

Where rays reach a depth z = depth.

transmit_apex_distance(transmit_origins, ...)

Find the point on the central axis that a set of transmits fans out from.

virtual_apex_distance(probe_geometry, max_angle)

Distance [m] behind the middle of a flat array of the point whose sector edges, at +-max_angle, pass through the ends of the array: (aperture / 2) / tan(max_angle).

zea.beamform.geometry.SINC_HALF_AMPLITUDE = 0.6033545644016143¶

The argument x at which sinc(x) = sin(pi x) / (pi x) drops to 0.5 (-6 dB).

zea.beamform.geometry.STEERING_TOLERANCE = 1e-06¶

Polar angles at or below this magnitude [rad] count as unsteered. Converted data stores a nominally unsteered scan as float noise rather than exact zeros.

zea.beamform.geometry.compute_element_normals(probe_geometry, eps=1e-12)[source]¶

Estimate per-element unit surface normals from element positions.

zea’s built-in receive f-number apodization (zea.beamform.beamformer.fnumber_mask()) measures the acceptance cone relative to each element’s surface normal. For a flat linear array every element faces +z and the normal is trivial, but for a curved/convex array the peripheral elements are physically tilted outward, so their true look-direction is not +z. Assuming +z for those elements needlessly clips the receive aperture at the lateral edges of the sector. This function derives each element’s outward normal directly from probe_geometry so no extra probe metadata (radius of curvature, per element angles, …) is required.

The array is treated as a 1-D curve of elements ordered along the aperture lying in the x-z imaging plane (zea’s convention; the medium is at +z). For each element the local tangent d is estimated by central finite differences of neighbouring element positions (one-sided at the two ends). The outward normal is the depth axis +z with its component along the tangent removed:

n = normalize(z_hat - (z_hat.d) / (d.d) * d)

This yields exactly (0, 0, 1) for a flat array (any spacing, ordered or not — the z column is identically zero, so the rejection leaves z_hat untouched), so existing linear-array reconstructions are unchanged bit-for-bit. For a convex arc it recovers the exact radial outward normal at the interior elements.

Parameters:
  • probe_geometry (Tensor) – Element positions (x, y, z) of shape (n_el, 3) in metres, ordered along the array.

  • eps (float) – Small value guarding the tangent-length division.

Returns:

Unit outward normals of shape (n_el, 3).

Return type:

Tensor

Notes

  • Intended for 1-D arrays (linear / phased / curved) in the x-z plane. For a genuine 3-D matrix array (elements spread in y) a single index-ordered tangent is not meaningful, so the function falls back to +z for every element when the geometry has a non-negligible y extent — reproducing today’s behaviour.

  • A single-element array falls back to +z.

zea.beamform.geometry.element_acceptance_angle(element_width, wavelength)[source]¶

Half-angle within which a single element receives, at -6 dB.

Uses the same rigid-baffle directivity model as zea.func.ultrasound.directivity(), sinc(element_width / wavelength * sin(theta)), which drops to 0.5 at sin(theta) = 0.603 * wavelength / element_width. Elements narrower than about 0.6 wavelength never drop that far and receive over the whole half-space.

Parameters:
  • element_width (float) – Element width [m].

  • wavelength (float) – Wavelength [m].

Returns:

The acceptance half-angle [rad], at most pi / 2.

Return type:

float

zea.beamform.geometry.element_pitch(probe_geometry)[source]¶

Median distance between neighbouring elements in metres.

The distance is measured along the array rather than along x, so this also works for curved arrays. Use zea.probes.Probe.get_pitch() to also reject geometries that have no single pitch.

Parameters:

probe_geometry (np.ndarray) – Element positions of shape (n_el, 3), ordered along the array.

Returns:

The median element spacing, or nan for a single element.

Return type:

float

zea.beamform.geometry.insonified_edge_rays(probe_geometry, transmit_origins, polar_angles, focus_distances, element_normals=None)[source]¶

Edge rays bounding the region each transmit insonifies, in the x-z plane.

  • Focused transmit (positive, finite focus): its axis, from its origin along its angle. It insonifies a narrow beam, so it adds no width.

  • Plane wave (inf or 0 focus): from the two end elements of the array along the steering angle, tilted with each end element’s normal (which makes an unsteered plane wave on a curved array span the array’s angular range).

  • Diverging wave (negative focus): from its virtual source through the two end elements of the array.

Parameters:
  • probe_geometry (np.ndarray) – Element positions of shape (n_el, 3).

  • transmit_origins (np.ndarray) – Transmit origins of shape (n_tx, 3).

  • polar_angles (np.ndarray) – Steering angles of shape (n_tx,) [rad].

  • focus_distances (np.ndarray) – Focus distances of shape (n_tx,) [m].

  • element_normals (np.ndarray, optional) – Unit element normals of shape (n_el, 3). Defaults to compute_element_normals(), which estimates the end elements’ normals from their last neighbour, half an element short on a curved array; pass the exact normals when they are known.

Returns:

Start points and unit directions of the rays, both of shape (n_rays, 2) as (x, z).

Return type:

tuple[np.ndarray, np.ndarray]

zea.beamform.geometry.is_diverging(focus_distances)[source]¶

Mask of the transmits that are diverging waves.

A diverging wave has a finite, negative focus distance (a virtual source behind the array).

Parameters:

focus_distances – Focus distance per transmit, scalar or array. NaN marks no transmit type.

Returns:

Boolean mask with the shape of focus_distances.

Return type:

np.ndarray

zea.beamform.geometry.is_focused(focus_distances)[source]¶

Mask of the transmits that are focused.

A focused transmit has a finite, positive focus distance.

Parameters:

focus_distances – Focus distance per transmit, scalar or array. NaN marks no transmit type.

Returns:

Boolean mask with the shape of focus_distances.

Return type:

np.ndarray

zea.beamform.geometry.is_plane_wave(focus_distances)[source]¶

Mask of the transmits that are plane waves.

A plane wave is marked by an infinite focus distance (np.inf, the canonical value) or by 0.

Parameters:

focus_distances – Focus distance per transmit, scalar or array. NaN marks no transmit type.

Returns:

Boolean mask with the shape of focus_distances.

Return type:

np.ndarray

zea.beamform.geometry.rays_at_depth(points, directions, depth)[source]¶

Where rays reach a depth z = depth.

Rays that start below depth are evaluated at their start point.

Parameters:
  • points (np.ndarray) – Ray start points of shape (n_rays, 2) as (x, z).

  • directions (np.ndarray) – Unit directions of shape (n_rays, 2).

  • depth (float) – The depth [m].

Returns:

Points of shape (n_rays, 2); nan for rays that never reach depth because they point sideways or backwards.

Return type:

np.ndarray

zea.beamform.geometry.transmit_apex_distance(transmit_origins, polar_angles, focus_distances, tol)[source]¶

Find the point on the central axis that a set of transmits fans out from.

Two transmit schemes define such a point:

  • Steered focused transmits whose axes (from transmit_origins along polar_angles) cross x = 0 in one point, next to which any unsteered focused transmits start on the central axis. That is the array middle for transmits launched from there, a virtual apex behind the array for transmits spread over a flat array, and the centre of curvature for transmits along a curved array’s normals. Steered plane and diverging waves do not fan out from their origin (it only references their delays), so their axes define no point.

  • Unsteered diverging waves that share one virtual source (transmit_origins + focus_distances along +z) on the central axis.

Parameters:
  • transmit_origins (np.ndarray) – Transmit origins of shape (n_tx, 3) [m].

  • polar_angles (np.ndarray) – Steering angles of shape (n_tx,) [rad].

  • focus_distances (np.ndarray) – Focus distances of shape (n_tx,) [m] (negative for diverging waves).

  • tol (float) – How far apart [m] the crossings may be and still count as one point. zea.Parameters uses half the element pitch, the same tolerance as zea.probes.fit_curved_probe_radius().

Returns:

The distance [m] from the middle of the array back to that point (>= 0), or None when the transmits define no single point.

Return type:

float | None

zea.beamform.geometry.virtual_apex_distance(probe_geometry, max_angle)[source]¶

Distance [m] behind the middle of a flat array of the point whose sector edges, at +-max_angle, pass through the ends of the array: (aperture / 2) / tan(max_angle).

Parameters:
  • probe_geometry (np.ndarray) – Element positions of shape (n_el, 3).

  • max_angle (float) – Half-angle of the sector [rad].

Returns:

The distance, or 0.0 (the array middle) for a sector no wider than STEERING_TOLERANCE, or of pi / 2 or more.

Return type:

float