PatternStm
PatternStm は, ハードウェアタイマにより任意の音場 (各振動子の位相・振幅) を切り替える STM 機能を提供する.
FociStm と異なり, 任意の Pattern を扱えるが, 転送データ量が多い (=レイテンシが大きい).
PatternStm::new(config, &patterns, intensities, option);PatternStm(config, patterns, intensities, option)new PatternStm(config, patterns, intensities, option);| 引数 | 型 | 説明 |
|---|---|---|
config |
SamplingConfig |
サンプル毎のサンプリング設定 |
phases |
&[Vec<Vec<Phase>>] |
各サンプルの位相の列 (2 サンプル以上) |
intensities |
impl Into<StmIntensity> |
全サンプルの振幅 (一様値 / 全 index 共通バッファ / index 毎のバッファ列) |
option |
PatternStmOption |
位相のビット幅・ループ・遷移などのオプション |
config は 1 サンプルあたりのサンプリング設定である.
intensities には以下の3つの型が渡せる.
Intensity: 全デバイス・全振動子・全indexで同じ値を使う場合&[Vec<Intensity>]: 振動子ごとには異なるが全indexで共通の値を使う場合&[Vec<Vec<Intensity>>]: 全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,}| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
bank |
PatternBank |
PatternBank::B0 |
書き込み先・再生対象のバンク |
phase_depth |
PhaseDepth |
PhaseDepth::Bits8 |
位相のビット幅 |
loop_behavior |
LoopBehavior |
LoopBehavior::Infinite |
ループ回数 |
transition_mode |
TransitionMode |
TransitionMode::Immediate |
バンク切替時の遷移タイミング |
loop_behavior と transition_mode の挙動は再生制御 を参照.
intensities |
PhaseDepth::Bits8 |
PhaseDepth::Bits4 |
|---|---|---|
Intensity |
WritePatternPhase (5 index/フレーム) |
WritePatternPhase (11 index/フレーム) |
&[Vec<Intensity>] / &[Vec<Vec<Intensity>>] |
WritePatternBuffer (2 index/フレーム) |
エラー |
Bits4 は位相を上位 4 bit に量子化する.
等価な低レベルコマンド
Section titled “等価な低レベルコマンド”PatternStm は内部で WritePatternPhase または WritePatternBuffer + ConfigPattern + ActivatePatternBank の 3 つへ展開される.
以下は intensities が一様値のときの PatternStm::new(config, &phases, intensities, option) と等価な組み合わせである.
intensities が振動子ごとの値のときは WritePatternPhase の代わりに WritePatternBuffer が 2 index ずつ使われる.
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, }));