これは開発版のドキュメントである. 内容は次のリリースまでに変更される可能性がある. 最新のリリース版は 0.9.x を参照.
PatternStm
PatternStm は, ハードウェアタイマにより任意の音場 (各振動子の位相・振幅) を切り替える STM 機能を提供する.
FociStm と異なり, 任意の Pattern を扱えるが, 転送フレーム数が多い (=レイテンシが大きい).
PatternStm::new(freq, &patterns, intensities, option);PatternStm(freq, patterns, intensities, option)new PatternStm(freq, patterns, intensities, option);| 引数 | 型 | 説明 |
|---|---|---|
freq |
impl Into<StmConfig> |
再生レート (Freq / Duration / SamplingConfig) |
phases |
&[Vec<Vec<Phase>>] |
各サンプルの位相の列 (2 サンプル以上) |
intensities |
impl Into<StmIntensity> |
全サンプルの振幅 (一様値 / 全 index 共通バッファ / index 毎のバッファ列) |
option |
PatternStmOption |
転送モード・ループ・遷移などのオプション |
freq に Freq / Duration を渡すと「全サンプルを 1 周する周波数/周期」を表す.
サンプリング周波数を指定することもできる.
Duration がサンプル数で割り切れない場合はエラーになる (丸めたいときは Nearest を使う).
intensities には以下の3つの型が渡せる.
Intensity: 全デバイス・全振動子・全indexで同じ値を使う場合&[Vec<Intensity>]: 振動子ごとには異なるが全indexで共通の値を使う場合&[Vec<Vec<Intensity>>]: 全indexごとに異なる値を使う場合
PatternStmOption
Section titled “PatternStmOption”PatternStmOption { bank, mode, loop_behavior, transition_mode, ..Default::default()}PatternStmOption( bank, mode, loop_behavior, transition_mode,)new PatternStmOption{ Bank = bank, Mode = mode, LoopBehavior = loopBehavior, TransitionMode = 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, &phases, intensities, option) と等価な組み合わせである.
PatternStmMode が PhaseFull / PhaseHalf のときは, WritePatternBuffer の代わりに WritePatternCompressed が使われる (このとき intensities は Intensity (一様値) しか渡せず, それ以外はエラーになる).
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,};for index, phases in enumerate(patterns): WritePatternBuffer( bank=option.bank, index=index, phases=phases, intensities=intensities, )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, phases: patterns[index], intensities: intensities );}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::{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?;import asyncioimport math
import numpy as np
from autd3 import Client, ClientConfigfrom autd3.commands import PatternStm, PatternStmMode, PatternStmOptionfrom autd3.geometry import Autd3, Geometryfrom autd3.units import Hz, m, sfrom autd3.value import Intensity, LoopBehavior, PatternBank, TransitionModefrom autd3_link_nop import Nopfrom autd3_pattern import focusfrom autd3_pattern import wavelength as calc_wavelength
async def main() -> None: geometry = Geometry([Autd3([0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0])]) async with await Client.open(geometry, Nop(), ClientConfig()) as client: center = geometry.center() + np.array([0.0, 0.0, 150.0]) wavelength = calc_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.phase_buffer() focus( geometry, target, wavelength, buffer, ) patterns.append(buffer)
builder = client.datagram_builder() builder.push( PatternStm( 1.0 * Hz, patterns, Intensity.MAX, 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)
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) });await using 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 PhaseBuffer[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.PhaseBuffer(); Pattern.Focus( geometry, target, wavelength, buffer ); patterns[i] = buffer;}
var builder = client.DatagramBuilder();builder.Push(new PatternStm( 1.0f * Hz, patterns, Intensity.Max, 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);}