Skip to content

Holo

Holo is a set of Pattern computations for generating multiple focal points (control points) simultaneously. It optimizes the phase and amplitude of each transducer so that the target sound pressure is obtained at the specified multiple points.

The provided algorithms are as follows.

  • Naive — single-step back-propagation
  • GS — Gerchberg-Saxton method
  • GS-PAT — GS-PAT method
  • Greedy — combinatorial optimization that greedily determines the phase

A struct representing a focal point. It holds a position and a target amplitude.

The target amplitude Amplitude is constructed by multiplying an f32 by an amplitude unit.

The amplitude obtained from the optimization may be an intensity that the transducer cannot output as-is. Therefore, a constraint is specified for converting the amplitude obtained from the optimization into the transducer intensity to be output.

Normalize Normalizes by the maximum value
Multiply(f32) Multiplies by a coefficient after normalization and clamps
Uniform(Intensity) Sets all transducers to a constant intensity
Clamp(Intensity, Intensity) Clamps the amplitude to the specified range

It is specified via the constraint field of each Option. The default differs depending on the algorithm.

The directivity model of the transducer. Either the omnidirectional Sphere (default) or the real-hardware directivity T4010A1 can be chosen. It is specified via the directivity field of each Option.

Selects the transducers to include in the optimization. It is specified via the mask field of each Option (the default is AllEnabled).

  • TransducerMask::AllEnabled — uses all transducers (default).
  • TransducerMask::Masked(&[Vec<bool>]) — specifies enabled/disabled for each transducer individually.

naive / gs / gspat delegate linear algebra operations to the LinAlgBackend trait. NalgebraBackend is used as the standard implementation. The backend is passed as the first argument of each function.

greedy does not use matrix operations, so it does not take a backend.

WgpuBackend is a backend that performs calculations on the GPU.

naive / gs / gspat each have a naive_batch / gs_batch / gspat_batch counterpart that solves several independent problems at once.

let problems = 64;
let foci: Vec<AmplitudeTarget> = (0..problems)
.map(|i| AmplitudeTarget {
point: center + offset(i as f32 * 0.5 * mm, 0.0 * mm, 0.0 * mm),
amplitude: 5e3 * Pa,
})
.collect();
let mut dst = vec![geometry.pattern_buffer(); problems];
gs_batch(
&NalgebraBackend,
&geometry,
&foci,
wavelength,
&option,
&mut dst,
)?;

The problem count is determined by the length of dst. The foci are passed as a slice of length equal to the number of problems multiplied by the number of foci per problem. An error is returned if the length of the slice is not divisible by the length of dst.

The gain comes from GPU backends, NalgebraBackend does not get faster.