Skip to content

PatternStm

PatternStm provides an STM feature that switches arbitrary sound fields (the emission of each transducer) by a hardware timer. Unlike FociStm, it can handle arbitrary Patterns, but the number of frames to transfer is large (i.e. the latency is high).

PatternStm::new(freq, &patterns, option);
Parameter Type Description
freq impl Into<StmConfig> Playback rate (Freq / Duration / SamplingConfig)
patterns &[Vec<Vec<Emission>>] Sequence of Pattern samples (at least 2 samples)
option PatternStmOption Options such as transfer mode, 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).

PatternStmOption {
bank,
mode,
loop_behavior,
transition_mode,
}
Field Type Default Description
bank PatternBank PatternBank::B0 Bank to write to / play back
mode PatternStmMode PatternStmMode::PhaseIntensityFull Transfer format
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.

Selects the transfer format of each Pattern. The phase-only and low-resolution formats can reduce the number of frames to transfer.

Mode Content
PhaseIntensityFull Transfer phase and amplitude as-is (default)
PhaseFull Transfer phase only. Amplitude fixed at maximum
PhaseHalf Compress phase to 4 bit and transfer

PatternStm internally expands into the three commands WritePatternBuffer (each index) + ConfigPattern + ChangePatternBank. The following is equivalent to PatternStm::new(freq, &patterns, option).

When PatternStmMode is PhaseFull / PhaseHalf, WritePatternCompressed is used instead of WritePatternBuffer.

for (index, pattern) in patterns.iter().enumerate() {
WritePatternBuffer {
bank: option.bank,
index,
emissions: pattern.as_slice(),
};
}
ConfigPattern {
bank: option.bank,
config: StmConfig::new(freq).into_sampling_config(patterns.len()),
size: patterns.len(),
loop_behavior: option.loop_behavior,
};
ChangePatternBank {
bank: option.bank,
transition_mode: option.transition_mode,
};
use autd3_rs::commands::{PatternStm, PatternStmMode, PatternStmOption};
use autd3_rs::geometry::{Autd3, Geometry, offset};
use autd3_rs::units::{Hz, m, mm, s};
use autd3_rs::value::{LoopBehavior, PatternBank, TransitionMode};
use autd3_rs::{Client, ClientConfig};
use autd3_rs_link_nop::Nop;
use autd3_rs_pattern::{FocusOption, focus, wavelength};
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 wavelength = wavelength(340.0 * m / s);
let patterns = (0..200)
.map(|i| {
let theta = 2.0 * std::f32::consts::PI * i as f32 / 200.0;
let target =
center + offset(30.0 * theta.cos() * mm, 30.0 * theta.sin() * mm, 0.0 * mm);
let mut buffer = geometry.pattern_buffer();
focus(
&geometry,
target,
wavelength,
&FocusOption::default(),
&mut buffer,
);
buffer
})
.collect::<Vec<_>>();
let mut builder = client.datagram_builder();
builder.push(PatternStm::new(
1.0 * Hz,
&patterns,
PatternStmOption {
bank: PatternBank::B0,
mode: PatternStmMode::PhaseIntensityFull,
loop_behavior: LoopBehavior::Infinite,
transition_mode: TransitionMode::Immediate,
},
));
let frames = builder.build()?;
for frame in &frames {
client.send_checked(frame).await?;
}
client.close().await?;