Skip to content

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);
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).

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 }N focal points and an amplitude.
FociStmOption {
bank,
sound_speed,
loop_behavior,
transition_mode,
}
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 are provided to generate typical trajectories.

circle(center, radius, num_points, normal, intensity, &mut 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);
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.

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,
};
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?;