コンテンツにスキップ
これは開発版のドキュメントである. 内容は次のリリースまでに変更される可能性がある. 最新のリリース版は 0.9.x を参照.

PatternStm

PatternStm は, ハードウェアタイマにより任意の音場 (各振動子の位相・振幅) を切り替える STM 機能を提供する. FociStm と異なり, 任意の Pattern を扱えるが, 転送フレーム数が多い (=レイテンシが大きい).

PatternStm::new(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 {
bank,
mode,
loop_behavior,
transition_mode,
..Default::default()
}
フィールド 型 デフォルト 説明
bank PatternBank PatternBank::B0 書き込み先・再生対象のバンク
mode PatternStmMode PatternStmMode::PhaseIntensityFull 転送形式
loop_behavior LoopBehavior LoopBehavior::Infinite ループ回数
transition_mode TransitionMode TransitionMode::Immediate バンク切替時の遷移タイミング

loop_behavior と transition_mode の挙動は再生制御 を参照.

各 Pattern の転送形式を選ぶ. 位相のみ・低分解能の形式は転送フレーム数を減らせる.

モード 内容
PhaseIntensityFull 位相・振幅をそのまま転送 (デフォルト)
PhaseFull 位相と一様な振幅を転送
PhaseHalf 4 bit に圧縮した位相と一様な振幅を転送

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,
};
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?;