Holo

Holo is a Gain for generating multiple foci. Several algorithms for generating multiple foci have been proposed, and the following algorithms are implemented in SDK.

  • Naive - Linear synthesis of single-focus solutions
  • GS - Gershberg-Saxon, based on Marzo et al.1
  • GSPAT - Gershberg-Saxon for Phased Arrays of Transducers, based on Plasencia et al.2
  • LM - Levenberg-Marquardt, LM method proposed by Levenberg 3 and Marquardt 4 for optimization of nonlinear least-squares problems, implementation based on Madsen's text5
  • Greedy - Greedy algorithm and Brute-force search, based on Suzuki et al.6

You can select the backend for the calculation of the algorithm from the following.

  • NalgebraBackend - uses Nalgebra
  • CUDABackend - uses CUDA, which runs on GPUs (only available in Rust)
use autd3::prelude::*;
use autd3_gain_holo::{NalgebraBackend, GSPAT, Pa};

#[allow(unused_variables)]
fn main() {
let x1 = 0.;
let y1 = 0.;
let z1 = 0.;
let x2 = 0.;
let y2 = 0.;
let z2 = 0.;
let backend = std::sync::Arc::new(NalgebraBackend::default());
let g = GSPAT::new(
      backend,
      [
          (Point3::new(x1, y1, z1), 5e3 * Pa),
          (Point3::new(x2, y2, z2), 5e3 * Pa),
      ],
  );
}
#include<autd3.hpp>
#include "autd3/gain/holo.hpp"

using autd3::gain::holo::Pa;
int main() {
const auto x1 = 0.0;
const auto y1 = 0.0;
const auto z1 = 0.0;
const auto x2 = 0.0;
const auto y2 = 0.0;
const auto z2 = 0.0;
std::vector<std::pair<autd3::Point3, autd3::gain::holo::Amplitude>> foci = {
    {autd3::Point3(x1, y1, z1), 5e3 * autd3::gain::holo::Pa},
    {autd3::Point3(x2, y2, z2), 5e3 * autd3::gain::holo::Pa},
};
const auto backend = std::make_shared<autd3::gain::holo::NalgebraBackend>();
auto g = autd3::gain::holo::GSPAT(backend, foci);
return 0; }
using AUTD3Sharp.Gain.Holo;

using AUTD3Sharp.Utils;
using static AUTD3Sharp.Units;
var x1 = 0.0f;
var y1 = 0.0f;
var z1 = 0.0f;
var x2 = 0.0f;
var y2 = 0.0f;
var z2 = 0.0f;
var backend = new NalgebraBackend();
var g = new GSPAT(backend, [
                        (new Point3(x1, y1, z1), 5e3f * Pa),
                        (new Point3(x2, y2, z2), 5e3f * Pa)
                    ]);
import numpy as np
from pyautd3.gain.holo import GSPAT, NalgebraBackend, Pa

x1 = 0.0
y1 = 0.0
z1 = 0.0
x2 = 0.0
y2 = 0.0
z2 = 0.0
backend = NalgebraBackend()
g = GSPAT(
    backend,
    [(np.array([x1, y1, z1]), 5e3 * Pa), (np.array([x2, y2, z2]), 5e3 * Pa)],
)

The constructor argument of each algorithm is backend.

The add_focus function specifies the position of each focus and the amplitude.

Amplitude constraint

Each algorithm's calculation result must be limited to the range that the transducer can output. This can be controlled by with_constraint, and one of the following four must be specified.

  • DontCare: Do nothing.
  • Normalize: Divide the amplitude of all transducers by the maximum amplitude and normalize it.
  • Uniform: Set the amplitude of all transducers to the specified value.
  • Clamp: Clamp the amplitude to the specified range.
use autd3::prelude::*;
use autd3_gain_holo::{EmissionConstraint, NalgebraBackend, Pa, GSPAT};
#[allow(unused_variables)]
fn main() {
    let x1 = 0.;
    let y1 = 0.;
    let z1 = 0.;
    let x2 = 0.;
    let y2 = 0.;
    let z2 = 0.;
    let foci = [
        (Point3::new(x1, y1, z1), 5e3 * Pa),
        (Point3::new(x2, y2, z2), 5e3 * Pa),
    ];
let backend = std::sync::Arc::new(NalgebraBackend::default());
let g =
    GSPAT::new(backend, foci).with_constraint(EmissionConstraint::Uniform(EmitIntensity::MAX));
}
#include<autd3.hpp>
#include <limits>
#include "autd3/gain/holo.hpp"
int main() {
const auto x1 = 0.0;
const auto y1 = 0.0;
const auto z1 = 0.0;
const auto x2 = 0.0;
const auto y2 = 0.0;
const auto z2 = 0.0;
std::vector<std::pair<autd3::Point3, autd3::gain::holo::Amplitude>> foci = {
    {autd3::Point3(x1, y1, z1), 5e3 * autd3::gain::holo::Pa},
    {autd3::Point3(x2, y2, z2), 5e3 * autd3::gain::holo::Pa},
};
const auto backend = std::make_shared<autd3::gain::holo::NalgebraBackend>();
auto g = autd3::gain::holo::GSPAT(backend, foci)
             .with_constraint(autd3::gain::holo::EmissionConstraint::Uniform(
                 std::numeric_limits<autd3::EmitIntensity>::max()));
return 0; }
using AUTD3Sharp.Gain.Holo;
using AUTD3Sharp;
using AUTD3Sharp.Utils;
using static AUTD3Sharp.Units;
var backend = new NalgebraBackend();
var x1 = 0.0f;
var y1 = 0.0f;
var z1 = 0.0f;
var x2 = 0.0f;
var y2 = 0.0f;
var z2 = 0.0f;
var foci = new[] { (new Point3(x1, y1, z1), 5e3f * Pa), (new Point3(x2, y2, z2), 5e3f * Pa) };
var g = new GSPAT(backend, foci)
                .WithConstraint(EmissionConstraint.Uniform(EmitIntensity.Max));
import numpy as np
from pyautd3 import EmitIntensity
from pyautd3.gain.holo import GSPAT, EmissionConstraint, NalgebraBackend, Pa

backend = NalgebraBackend()
x1 = 0.0
y1 = 0.0
z1 = 0.0
x2 = 0.0
y2 = 0.0
z2 = 0.0
foci = [(np.array([x1, y1, z1]), 5e3 * Pa), (np.array([x2, y2, z2]), 5e3 * Pa)]
g = GSPAT(backend, foci).with_constraint(
    EmissionConstraint.Uniform(EmitIntensity.maximum()),
)

Optimization parameters

Each algorithm has additional parameters. These are all specified by with_xxx.

use std::num::NonZeroUsize;
use autd3::prelude::*;
use autd3_gain_holo::{NalgebraBackend, GSPAT, Pa};
#[allow(unused_variables)]
fn main() {
let x1 = 0.;
let y1 = 0.;
let z1 = 0.;
let x2 = 0.;
let y2 = 0.;
let z2 = 0.;
let backend = std::sync::Arc::new(NalgebraBackend::default());
let g = GSPAT::new(
        backend,
        [
            (Point3::new(x1, y1, z1), 5e3 * Pa),
            (Point3::new(x2, y2, z2), 5e3 * Pa),
        ],
    )
    .with_repeat(NonZeroUsize::new(100).unwrap());
}
#include<autd3.hpp>
#include "autd3/gain/holo.hpp"
int main() {
const auto x1 = 0.0;
const auto y1 = 0.0;
const auto z1 = 0.0;
const auto x2 = 0.0;
const auto y2 = 0.0;
const auto z2 = 0.0;
std::vector<std::pair<autd3::Point3, autd3::gain::holo::Amplitude>> foci = {
    {autd3::Point3(x1, y1, z1), 5e3 * autd3::gain::holo::Pa},
    {autd3::Point3(x2, y2, z2), 5e3 * autd3::gain::holo::Pa},
};
const auto backend = std::make_shared<autd3::gain::holo::NalgebraBackend>();
auto g = autd3::gain::holo::GSPAT(backend, foci).with_repeat(100);
return 0; }
using AUTD3Sharp.Gain.Holo;
using AUTD3Sharp.Utils;
using static AUTD3Sharp.Units;
var backend = new NalgebraBackend();
var x1 = 0.0f;
var y1 = 0.0f;
var z1 = 0.0f;
var x2 = 0.0f;
var y2 = 0.0f;
var z2 = 0.0f;
var foci = new[] { (new Point3(x1, y1, z1), 5e3f * Pa), (new Point3(x1, y1, z1), 5e3f * Pa) };
var g = new GSPAT(backend, foci).WithRepeat(100);
from pyautd3.gain.holo import GSPAT, NalgebraBackend
from pyautd3.gain.holo import Pa
import numpy as np
backend = NalgebraBackend()
x1 = 0.0
y1 = 0.0
z1 = 0.0
x2 = 0.0
y2 = 0.0
z2 = 0.0
foci = [(np.array([x1, y1, z1]), 5e3 * Pa), (np.array([x2, y2, z2]), 5e3 * Pa)]
g = GSPAT(backend, foci).with_repeat(100)

Please refar to each paper for more details.

1

Marzo, Asier, and Bruce W. Drinkwater. "Holographic acoustic tweezers." Proceedings of the National Academy of Sciences 116.1 (2019): 84-89.

2

Plasencia, Diego Martinez, et al. "GS-PAT: high-speed multi-point sound-fields for phased arrays of transducers." ACM Transactions on Graphics (TOG) 39.4 (2020): 138-1.

3

Levenberg, Kenneth. "A method for the solution of certain non-linear problems in least squares." Quarterly of applied mathematics 2.2 (1944): 164-168.

4

Marquardt, Donald W. "An algorithm for least-squares estimation of nonlinear parameters." Journal of the society for Industrial and Applied Mathematics 11.2 (1963): 431-441.

5

Madsen, Kaj, Hans Bruun Nielsen, and Ole Tingleff. "Methods for non-linear least squares problems." (2004).

6

Suzuki, Shun, et al. "Radiation Pressure Field Reconstruction for Ultrasound Midair Haptics by Greedy Algorithm with Brute-Force Search." IEEE Transactions on Haptics (2021).