FociStm
FociStm provides an STM feature that switches single- and multi-focus sound fields by a hardware timer.
Unlike PatternStm, it can only handle focal points, but multiple focal points fit in a single frame, so the number of frames is small and the latency is low.
FociStm::new(freq, &points, option);FociStm(freq, points, option)new FociStm(freq, points, option);| Parameter | Type | Description |
|---|---|---|
freq |
impl Into<StmConfig> |
Playback rate (Freq / Duration / SamplingConfig) |
points |
&[ControlPoints<N>] |
Sequence of focal point samples (at least 2 samples) |
option |
FociStmOption |
Options such as sound speed, loop, and transition |
Passing a Freq / Duration to freq represents “the frequency/period for one full cycle over all samples”.
A sampling frequency can also be specified.
A Duration that is not divisible by the number of samples is an error (use Nearest to round it).
ControlPoint / ControlPoints
Section titled “ControlPoint / ControlPoints”A single sample is represented by ControlPoints<N>. N is the number of focal points emitted simultaneously (up to 8).
ControlPoint { point, phase_offset }— focal point coordinate [mm] and phase offset.ControlPoints<N> { points: [ControlPoint; N], intensity }—Nfocal points and an amplitude.
FociStmOption
Section titled “FociStmOption”FociStmOption { bank, sound_speed, loop_behavior, transition_mode,}FociStmOption( bank, sound_speed, loop_behavior, transition_mode,)new FociStmOption( bank, soundSpeed, loopBehavior, transitionMode)| Field | Type | Default | Description |
|---|---|---|---|
bank |
PatternBank |
PatternBank::B0 |
Bank to write to / play back |
sound_speed |
Velocity |
340 m/s |
Sound speed used for focus computation |
loop_behavior |
LoopBehavior |
LoopBehavior::Infinite |
Loop count |
transition_mode |
TransitionMode |
TransitionMode::Immediate |
Transition timing on bank switching |
For the behavior of loop_behavior and transition_mode, see playback control.
Helper Functions
Section titled “Helper Functions”Helper functions are provided to generate typical trajectories.
circle
Section titled “circle”circle(center, radius, num_points, normal, intensity, &mut dst);circle(center, radius, num_points, normal, intensity, dst)Stm.Circle(center, radius, numPoints, normal, intensity, dst);| Parameter | Type | Description |
|---|---|---|
center |
Point3<f32> |
Center of the circle [mm] |
radius |
Length |
Radius of the circle |
num_points |
usize |
Number of points to generate |
normal |
UnitVector3<f32> |
Normal of the circle plane (unit vector) |
intensity |
Intensity |
Amplitude of each point |
dst |
&mut Vec<ControlPoints<1>> |
Output buffer |
Places num_points points at equal intervals on a circle whose normal is normal.
line(start, end, num_points, intensity, &mut dst);line(start, end, num_points, intensity, dst)Stm.Line(start, end, numPoints, intensity, dst);| Parameter | Type | Description |
|---|---|---|
start |
Point3<f32> |
Start point [mm] |
end |
Point3<f32> |
End point [mm] |
num_points |
usize |
Number of points to generate |
intensity |
Intensity |
Amplitude of each point |
dst |
&mut Vec<ControlPoints<1>> |
Output buffer |
Places num_points points at equal intervals along a line including the start and end points.
Equivalent Low-Level Commands
Section titled “Equivalent Low-Level Commands”FociStm is equivalent to the three commands WriteFociBuffer + ConfigFociStm + ChangePatternBank. When the data fits in a single frame it is fused and sent as one frame; otherwise it expands into the three commands above.
The following is equivalent to FociStm::new(freq, &points, option).
WriteFociBuffer { bank: option.bank, index_offset: 0, points: &points,};ConfigFociStm { bank: option.bank, config: StmConfig::new(freq).into_sampling_config(points.len()), size: points.len(), num_foci: N, // N is the number of foci in the points sound_speed: option.sound_speed, loop_behavior: option.loop_behavior,};ChangePatternBank { bank: option.bank, transition_mode: option.transition_mode,};WriteFociBuffer( bank=option.bank, index_offset=0, points=points,)ConfigFociStm( bank=option.bank, config=StmConfig(freq).into_sampling_config(len(points)), size=len(points), num_foci=num_foci, sound_speed=option.sound_speed, loop_behavior=option.loop_behavior,)ChangePatternBank( bank=option.bank, transition_mode=option.transition_mode,)new WriteFociBuffer( bank: option.Bank, indexOffset: 0, points: points);new ConfigFociStm( bank: option.Bank, config: new StmConfig(freq).IntoSamplingConfig(points.Length), size: (uint)points.Length, numFoci: numFoci, soundSpeed: option.SoundSpeed, loopBehavior: option.LoopBehavior);new ChangePatternBank( bank: option.Bank, transitionMode: option.TransitionMode);Example
Section titled “Example”use autd3_rs::commands::{FociStm, FociStmOption, circle};use autd3_rs::geometry::{Autd3, Geometry, Vector3, offset};use autd3_rs::units::{Hz, m, mm, s};use autd3_rs::value::{Intensity, LoopBehavior, PatternBank, TransitionMode};use autd3_rs::{Client, ClientConfig};use autd3_rs_link_nop::Nop;
let geometry = Geometry::new(vec![Autd3::default()]);let client = Client::open(&geometry, Nop, ClientConfig::default()).await?;
let center = geometry.center() + offset(0.0 * mm, 0.0 * mm, 150.0 * mm);let mut points = Vec::new();circle( center, 30.0 * mm, 200, Vector3::z_axis(), Intensity::MAX, &mut points,);
let mut builder = client.datagram_builder();builder.push(FociStm::new( 1.0 * Hz, &points, FociStmOption { bank: PatternBank::B0, sound_speed: 340.0 * m / s, loop_behavior: LoopBehavior::Infinite, transition_mode: TransitionMode::Immediate, },));let frames = builder.build()?;for frame in &frames { client.send_checked(frame).await?;}
client.close().await?;import asyncio
import numpy as np
from autd3 import Client, ClientConfigfrom autd3.commands import FociStm, FociStmOption, StmConfig, circlefrom autd3.geometry import Autd3, Geometryfrom autd3.units import Hz, m, sfrom autd3.value import Intensity, LoopBehavior, PatternBank, TransitionModefrom autd3_link_nop import Nop
async def main() -> None: geometry = Geometry([Autd3([0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0])]) client = await Client.open(geometry, Nop(), ClientConfig())
center = geometry.center() + np.array([0.0, 0.0, 150.0]) points = [] circle(center, 30.0, 200, [0.0, 0.0, 1.0], Intensity.MAX, points)
builder = client.datagram_builder() builder.push( FociStm( 1.0 * Hz, points, FociStmOption( bank=PatternBank.B0, sound_speed=340 * m / s, loop_behavior=LoopBehavior.Infinite, transition_mode=TransitionMode.Immediate, ), ) ) frames = builder.build() for frame in frames: await client.send_checked(frame)
await client.close()
asyncio.run(main())using System.Collections.Generic;using System.Numerics;using System.Threading.Tasks;using AUTD3;using AUTD3.Link;using Nop = AUTD3.Link.Nop;using static AUTD3.Units;
var geometry = new Geometry(new[] { new Autd3(Vector3.Zero) });var client = await Client.OpenAsync(geometry, new Nop(), new ClientConfig());
var center = geometry.Center + new Vector3(0.0f, 0.0f, 150.0f);var dst = new List<ControlPoints>();Stm.Circle( center, 30.0f * mm, 200, Vector3.UnitZ, Intensity.Max, dst);var points = dst.ToArray();
var builder = client.DatagramBuilder();builder.Push(new FociStm( 1.0f * Hz, points, new FociStmOption( bank: PatternBank.B0, soundSpeed: 340.0f * m / s, loopBehavior: LoopBehavior.Infinite, transitionMode: TransitionMode.Immediate )));var frames = builder.Build();foreach (var frame in frames){ await client.SendCheckedAsync(frame);}
await client.CloseAsync();