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 amount of data to transfer is large (i.e. the latency is high).
PatternStm::new(config, &patterns, intensities, option);PatternStm(config, patterns, intensities, option)new PatternStm(config, patterns, intensities, option);| Parameter | Type | Description |
|---|---|---|
config |
SamplingConfig |
Sampling configuration per sample |
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 phase depth, loop, and transition |
config is the sampling configuration per sample.
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
Section titled “PatternStmOption”PatternStmOption { bank, phase_depth, loop_behavior, transition_mode, ..Default::default()}PatternStmOption( bank, phase_depth, loop_behavior, transition_mode,)new PatternStmOption{ Bank = bank, PhaseDepth = phaseDepth, LoopBehavior = loopBehavior, TransitionMode = transitionMode,}| Field | Type | Default | Description |
|---|---|---|---|
bank |
PatternBank |
PatternBank::B0 |
Bank to write to / play back |
phase_depth |
PhaseDepth |
PhaseDepth::Bits8 |
Bit depth of the phase |
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.
Transfer Format
Section titled “Transfer Format”intensities |
PhaseDepth::Bits8 |
PhaseDepth::Bits4 |
|---|---|---|
Intensity |
WritePatternPhase (5 indices/frame) |
WritePatternPhase (11 indices/frame) |
&[Vec<Intensity>] / &[Vec<Vec<Intensity>>] |
WritePatternBuffer (2 indices/frame) |
Error |
Bits4 quantizes the phase to its upper 4 bits.
Equivalent Low-Level Commands
Section titled “Equivalent Low-Level Commands”PatternStm internally expands into the three commands WritePatternPhase or WritePatternBuffer + ConfigPattern + ActivatePatternBank.
The following is equivalent to PatternStm::new(config, &phases, intensities, option) when intensities is a uniform value.
When intensities holds per-transducer values, WritePatternBuffer is used for 2 indices at a time instead of WritePatternPhase.
let max_count = option.phase_depth.max_count();for (k, chunk) in patterns.chunks(max_count).enumerate() { WritePatternPhase { bank: option.bank, start_index: k * max_count, depth: option.phase_depth, intensity: intensities, patterns: chunk, };}ConfigPattern { bank: option.bank, config, size: patterns.len(), loop_behavior: option.loop_behavior,};ActivatePatternBank { bank: option.bank, transition_mode: option.transition_mode,};max_count = option.phase_depth.max_count()for start_index in range(0, len(patterns), max_count): WritePatternPhase( bank=option.bank, start_index=start_index, depth=option.phase_depth, intensity=intensities, patterns=patterns[start_index : start_index + max_count], )ConfigPattern( bank=option.bank, config=config, size=len(patterns), loop_behavior=option.loop_behavior,)ActivatePatternBank( bank=option.bank, transition_mode=option.transition_mode,)var maxCount = option.PhaseDepth.MaxCount();for (var startIndex = 0; startIndex < patterns.Length; startIndex += maxCount){ new WritePatternPhase( bank: option.Bank, startIndex: (ushort)startIndex, depth: option.PhaseDepth, intensity: intensities, patterns: patterns[startIndex..Math.Min(startIndex + maxCount, patterns.Length)] );}new ConfigPattern( bank: option.Bank, config: config, size: (uint)patterns.Length, loopBehavior: option.LoopBehavior);new ActivatePatternBank( bank: option.Bank, transitionMode: option.TransitionMode);Example
Section titled “Example”use autd3_rs::commands::{Clear, PatternStm, PatternStmOption, PhaseDepth, Synchronize};use autd3_rs::geometry::{Autd3, Geometry, offset};use autd3_rs::units::{Hz, m, mm, s};use autd3_rs::value::{Intensity, LoopBehavior, PatternBank, SamplingConfig, TransitionMode};use autd3_rs::Client;use autd3_rs::udp::TransportOption;use autd3_rs_pattern::{focus, wavelength};
let geometry = Geometry::new(vec![Autd3::default()]);let option = TransportOption::default();let mut client = Client::open(&geometry, &option).await?;client.send(Clear).await?;client.send(Synchronize).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<_>>();client.send(PatternStm::new( SamplingConfig::from_freq(1.0 * Hz * patterns.len() as f32)?, &patterns, Intensity::MAX, PatternStmOption { bank: PatternBank::B0, phase_depth: PhaseDepth::Bits8, loop_behavior: LoopBehavior::Infinite, transition_mode: TransitionMode::Immediate, ..Default::default() },)).await?;import asyncioimport math
from autd3 import Client, TransportOptionfrom autd3.commands import Clear, PatternStm, PatternStmOption, PhaseDepth, Synchronizefrom autd3.geometry import Autd3, Geometry, offsetfrom autd3.units import Hz, m, mm, sfrom autd3.value import Intensity, LoopBehavior, PatternBank, SamplingConfig, TransitionModefrom autd3_pattern import focusfrom autd3_pattern import wavelength as calc_wavelength
async def main() -> None: geometry = Geometry([Autd3()]) with await Client.open(geometry, TransportOption()) as client: await client.send(Clear()) await client.send(Synchronize())
center = geometry.center() + offset(0.0 * mm, 0.0 * mm, 150.0 * mm) wavelength = calc_wavelength(340 * m / s) patterns = [] for i in range(200): theta = 2.0 * math.pi * i / 200 target = center + offset(30.0 * math.cos(theta) * mm, 30.0 * math.sin(theta) * mm, 0.0 * mm) buffer = geometry.phase_buffer() focus( geometry, target, wavelength, buffer, ) patterns.append(buffer)
await client.send( PatternStm( SamplingConfig(1.0 * Hz * len(patterns)), patterns, Intensity.MAX, PatternStmOption( bank=PatternBank.B0, phase_depth=PhaseDepth.Bits8, loop_behavior=LoopBehavior.Infinite, transition_mode=TransitionMode.Immediate, ), ) )
asyncio.run(main())using System;using System.Threading.Tasks;using AUTD3;using static AUTD3.Units;
var geometry = new Geometry(new[] { new Autd3() });using var client = await Client.OpenAsync(geometry, new TransportOption());await client.SendAsync(new Clear());await client.SendAsync(new Synchronize());
var center = geometry.Center + Offset(0.0f * mm, 0.0f * mm, 150.0f * mm);var wavelength = Pattern.Wavelength(340.0f * m / s);var patterns = new PhaseBuffer[200];for (var i = 0; i < 200; i++){ var theta = 2.0f * MathF.PI * i / 200.0f; var target = center + Offset(30.0f * MathF.Cos(theta) * mm, 30.0f * MathF.Sin(theta) * mm, 0.0f * mm); var buffer = geometry.PhaseBuffer(); Pattern.Focus( geometry, target, wavelength, buffer ); patterns[i] = buffer;}
await client.SendAsync(new PatternStm( new SamplingConfig(1.0f * Hz * patterns.Length), patterns, Intensity.Max, new PatternStmOption { Bank = PatternBank.B0, PhaseDepth = PhaseDepth.Bits8, LoopBehavior = LoopBehavior.Infinite, TransitionMode = TransitionMode.Immediate, }));