これは開発版のドキュメントである. 内容は次のリリースまでに変更される可能性がある. 最新のリリース版は 0.6.x を参照.
送信モード
DatagramBuilder::build で得た Frames は複数のFrameに分かれうる.
Frameの送信方法は 2 つあり, 確実性とスループットがトレードオフになる.
以下では, 焦点を円周上で動かす例で 2 つの送信方法を比較する.
あらかじめ移動先となる焦点位置を targets として用意しておく.
// Prepare 1000 focus points along a circle 150 mm above the array center.let center = geometry.center() + offset(0.0 * mm, 0.0 * mm, 150.0 * mm);let targets: Vec<Point3<f32>> = (0..NUM_POINTS) .map(|i| { let theta = 2.0 * PI * i as f32 / NUM_POINTS as f32; center + offset( RADIUS_MM * theta.cos() * mm, RADIUS_MM * theta.sin() * mm, 0.0 * mm, ) }) .collect();# Prepare 1000 focus points along a circle 150 mm above the array center.center = geometry.center() + np.array([0.0, 0.0, 150.0])targets = [ center + np.array( [ RADIUS_MM * math.cos(2.0 * math.pi * i / NUM_POINTS), RADIUS_MM * math.sin(2.0 * math.pi * i / NUM_POINTS), 0.0, ] ) for i in range(NUM_POINTS)]// Prepare 1000 focus points along a circle 150 mm above the array center.var center = geometry.Center + new Vector3(0.0f, 0.0f, 150.0f);var targets = new Vector3[NumPoints];for (var i = 0; i < NumPoints; i++){ var theta = 2.0f * MathF.PI * i / NumPoints; targets[i] = center + new Vector3(RadiusMm * MathF.Cos(theta), RadiusMm * MathF.Sin(theta), 0.0f);}stop-and-wait
Section titled “stop-and-wait”1 フレームごとに応答を待ってから次を送る方式.
send_checked を使う.
各更新が確実に反映されたことを確認してから次へ進むため確実だが, 毎フレームで往復のレイテンシがかかるためスループットは低い.
let mut patterns = geometry.pattern_buffer();for &target in targets { autd3_rs_pattern::focus( geometry, target, wavelength, &autd3_rs_pattern::FocusOption::default(), &mut patterns, ); let mut builder = client.datagram_builder(); builder.push(Pattern::new(&patterns)); for frame in &builder.build()? { client.send_checked(frame).await?; }}patterns = geometry.pattern_buffer()for target in targets: pattern.focus( geometry, target, wavelength, pattern.FocusOption(), patterns, ) builder = client.datagram_builder() builder.push(Pattern(patterns)) for frame in builder.build(): await client.send_checked(frame)var patterns = geometry.PatternBuffer();foreach (var target in targets){ Pattern.Focus( geometry, target, wavelength, new FocusOption(), patterns ); var builder = client.DatagramBuilder(); builder.Push(new Pattern(patterns)); foreach (var frame in builder.Build()) { await client.SendCheckedAsync(frame); }}streaming
Section titled “streaming”応答を待たずに次々と送り, 後で応答をまとめて回収する方式.
send はフレームをキューに積んだ時点で ResponseFuture を返し, その ResponseFuture を await するとデバイスの応答 (Response) が得られる.
Response は check でデバイスエラーの有無を検証できる.
送信キューの最大サイズは MAX_INFLIGHT (127).
ResponseFuture を FIFO で保持し, キューが埋まったら最古の応答を回収する.
1 フレームごとに応答を待たないため, スループットが高い.
let mut patterns = geometry.pattern_buffer();let mut pending: VecDeque<ResponseFuture> = VecDeque::with_capacity(MAX_INFLIGHT);for &target in targets { autd3_rs_pattern::focus( geometry, target, wavelength, &autd3_rs_pattern::FocusOption::default(), &mut patterns, ); let mut builder = client.datagram_builder(); builder.push(Pattern::new(&patterns)); for frame in &builder.build()? { if pending.len() >= MAX_INFLIGHT { pending.pop_front().expect("non-empty").await?.check()?; } pending.push_back(client.send(frame).await?); }}// Drain the remaining responses.while let Some(fut) = pending.pop_front() { fut.await?.check()?;}patterns = geometry.pattern_buffer()pending = collections.deque()for target in targets: pattern.focus( geometry, target, wavelength, pattern.FocusOption(), patterns, ) builder = client.datagram_builder() builder.push(Pattern(patterns)) for frame in builder.build(): if len(pending) >= MAX_INFLIGHT: (await pending.popleft()).check() pending.append(await client.send(frame))# Drain the remaining responses.while pending: (await pending.popleft()).check()var patterns = geometry.PatternBuffer();var pending = new Queue<ResponseToken>();foreach (var target in targets){ Pattern.Focus( geometry, target, wavelength, new FocusOption(), patterns ); var builder = client.DatagramBuilder(); builder.Push(new Pattern(patterns)); foreach (var frame in builder.Build()) { if (pending.Count >= Client.MaxInflight) { (await pending.Dequeue()).Check(); } pending.Enqueue(await client.SendAsync(frame)); }}// Drain the remaining responses.while (pending.Count > 0){ (await pending.Dequeue()).Check();}初期化や設定など, 確実に 1 つずつ反映させたいコマンドは stop-and-wait.
焦点を高頻度で更新するなど, スループットが重要な場面では streaming を使う.
send / send_checked の詳細は Client を参照.