Skip to content
This is the development version of the documentation. It may change before the next release. See 0.9.x for the latest release.

PatternStm

PatternStm provides an STM feature that switches arbitrary sound fields (the phase and intensity 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, intensities, option);
Parameter Type Description
freq impl Into<StmConfig> Playback rate (Freq / Duration / SamplingConfig)
phases &[Vec<Vec<Phase>>] Phases of each sample (at least 2 samples)
intensities impl Into<StmIntensity> Intensities for every sample (a uniform value, one buffer shared by all indices, or one buffer per index)
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).

intensities accepts the following three types.

  • Intensity: to use the same value for every device, every transducer and every index
  • &[Vec<Intensity>]: to use values that differ per transducer but are shared by all indices
  • &[Vec<Vec<Intensity>>]: to use a different value for every index
PatternStmOption {
bank,
mode,
loop_behavior,
transition_mode,
..Default::default()
}
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 and a single uniform amplitude
PhaseHalf Transfer 4-bit phase and a single uniform amplitude

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

When PatternStmMode is PhaseFull / PhaseHalf, WritePatternCompressed is used instead of WritePatternBuffer (intensities must then be a uniform Intensity; anything else is an error).

for (index, phases) in patterns.iter().enumerate() {
WritePatternBuffer::new(option.bank, index, phases, intensities);
}
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::{Intensity, LoopBehavior, PatternBank, TransitionMode};
use autd3_rs::{Client, ClientConfig};
use autd3_rs_link_nop::Nop;
use autd3_rs_pattern::{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.phase_buffer();
focus(
&geometry,
target,
wavelength,
&mut buffer,
);
buffer
})
.collect::<Vec<_>>();
let mut builder = client.datagram_builder();
builder.push(PatternStm::new(
1.0 * Hz,
&patterns,
Intensity::MAX,
PatternStmOption {
bank: PatternBank::B0,
mode: PatternStmMode::PhaseIntensityFull,
loop_behavior: LoopBehavior::Infinite,
transition_mode: TransitionMode::Immediate,
..Default::default()
},
));
let frames = builder.build()?;
for frame in &frames {
client.send_checked(frame).await?;
}
client.close().await?;