PatternStm
PatternStm は, ハードウェアタイマにより任意の音場 (各振動子の emission) を切り替える STM 機能を提供する.
FociStm と異なり, 任意の Pattern を扱えるが, 転送フレーム数が多い (=レイテンシが大きい).
PatternStm::new(freq, &patterns, option);PatternStm(freq, patterns, option)new PatternStm(freq, patterns, option);| 引数 | 型 | 説明 |
|---|---|---|
freq |
impl Into<StmConfig> |
再生レート (Freq / Duration / SamplingConfig) |
patterns |
&[Vec<Vec<Emission>>] |
Pattern サンプルの列 (2 サンプル以上) |
option |
PatternStmOption |
転送モード・ループ・遷移などのオプション |
freq に Freq / Duration を渡すと「全サンプルを 1 周する周波数/周期」を表す.
サンプリング周波数を指定することもできる.
Duration がサンプル数で割り切れない場合はエラーになる (丸めたいときは Nearest を使う).
PatternStmOption
Section titled “PatternStmOption”PatternStmOption { bank, mode, loop_behavior, transition_mode,}PatternStmOption( bank, mode, loop_behavior, transition_mode,)new PatternStmOption( bank, mode, loopBehavior, transitionMode)| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
bank |
PatternBank |
PatternBank::B0 |
書き込み先・再生対象のバンク |
mode |
PatternStmMode |
PatternStmMode::PhaseIntensityFull |
転送形式 |
loop_behavior |
LoopBehavior |
LoopBehavior::Infinite |
ループ回数 |
transition_mode |
TransitionMode |
TransitionMode::Immediate |
バンク切替時の遷移タイミング |
loop_behavior と transition_mode の挙動は再生制御 を参照.
PatternStmMode
Section titled “PatternStmMode”各 Pattern の転送形式を選ぶ. 位相のみ・低分解能の形式は転送フレーム数を減らせる.
| モード | 内容 |
|---|---|
PhaseIntensityFull |
位相・振幅をそのまま転送 (デフォルト) |
PhaseFull |
位相のみ転送. 振幅は最大に固定 |
PhaseHalf |
位相を 4 bit に圧縮して転送 |
等価な低レベルコマンド
Section titled “等価な低レベルコマンド”PatternStm は内部で WritePatternBuffer (各 index) + ConfigPattern + ChangePatternBank の 3 つへ展開される.
以下は PatternStm::new(freq, &patterns, option) と等価な組み合わせである.
PatternStmMode が PhaseFull / PhaseHalf のときは, WritePatternBuffer の代わりに WritePatternCompressed が使われる.
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();