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);PatternStm(freq, patterns, option)new PatternStm(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
Section titled “PatternStmOption”PatternStmOption { bank, mode, loop_behavior, transition_mode,}PatternStmOption( bank, mode, loop_behavior, transition_mode,)new PatternStmOption( bank, mode, loopBehavior, transitionMode)| 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.
PatternStmMode
Section titled “PatternStmMode”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 |
Equivalent Low-Level Commands
Section titled “Equivalent Low-Level Commands”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,};for index, emissions in enumerate(patterns): WritePatternBuffer( bank=option.bank, index=index, emissions=emissions, )ConfigPattern( bank=option.bank, config=StmConfig(freq).into_sampling_config(len(patterns)), size=len(patterns), loop_behavior=option.loop_behavior,)ChangePatternBank( bank=option.bank, transition_mode=option.transition_mode,)for (var index = 0; index < patterns.Length; index++){ new WritePatternBuffer( bank: option.Bank, index: (ushort)index, emissions: patterns[index] );}new ConfigPattern( bank: option.Bank, config: new StmConfig(freq).IntoSamplingConfig(patterns.Length), size: (uint)patterns.Length, loopBehavior: option.LoopBehavior);new ChangePatternBank( bank: option.Bank, transitionMode: option.TransitionMode);Example
Section titled “Example”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?;import asyncioimport math
import numpy as np
from autd3 import Client, ClientConfigfrom autd3.commands import PatternStm, PatternStmMode, PatternStmOption, StmConfigfrom autd3.geometry import Autd3, Geometryfrom autd3.units import Hz, m, sfrom autd3.value import LoopBehavior, PatternBank, TransitionModefrom autd3_link_nop import Nopfrom autd3_pattern import FocusOption, focus, wavelength
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]) wl = wavelength(340 * m / s) patterns = [] for i in range(200): theta = 2.0 * math.pi * i / 200 target = center + np.array([30.0 * math.cos(theta), 30.0 * math.sin(theta), 0.0]) buffer = geometry.pattern_buffer() focus( geometry, target, wl, FocusOption(), buffer, ) patterns.append(buffer)
builder = client.datagram_builder() builder.push( PatternStm( 1.0 * Hz, patterns, PatternStmOption( bank=PatternBank.B0, mode=PatternStmMode.PhaseIntensityFull, 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;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 wavelength = Pattern.Wavelength(340.0f * m / s);var patterns = new PatternBuffer[200];for (var i = 0; i < 200; i++){ var theta = 2.0f * MathF.PI * i / 200.0f; var target = center + new Vector3(30.0f * MathF.Cos(theta), 30.0f * MathF.Sin(theta), 0.0f); var buffer = geometry.PatternBuffer(); Pattern.Focus( geometry, target, wavelength, new FocusOption(), buffer ); patterns[i] = buffer;}
var builder = client.DatagramBuilder();builder.Push(new PatternStm( 1.0f * Hz, patterns, new PatternStmOption( bank: PatternBank.B0, mode: PatternStmMode.PhaseIntensityFull, loopBehavior: LoopBehavior.Infinite, transitionMode: TransitionMode.Immediate )));var frames = builder.Build();foreach (var frame in frames){ await client.SendCheckedAsync(frame);}
await client.CloseAsync();