焦点の移動

autd3において, Gainは送信するたびに上書きされる. したがって, 次のようなコードを実行すると, 約1秒ごとに焦点の位置が移動する.

use autd3::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut autd = Controller::open([AUTD3::default()], Nop::new())?;
autd.send(Sine {
    freq: 150 * Hz,
    option: SineOption::default(),
})?;

let center = autd.center() + Vector3::new(0.0, 0.0, 150. * mm);
loop {
    autd.send(Focus {
        pos: center + Vector3::new(20. * mm, 0.0, 0.0),
        option: FocusOption::default(),
    })?;

    std::thread::sleep(std::time::Duration::from_secs(1));

    autd.send(Focus {
        pos: center - Vector3::new(20. * mm, 0.0, 0.0),
        option: FocusOption::default(),
    })?;

    std::thread::sleep(std::time::Duration::from_secs(1));
}
}
#include <chrono>
#include <thread>
#include "autd3.hpp"
#include "autd3/link/nop.hpp"
int main() {
auto autd = autd3::Controller::open({autd3::AUTD3{.pos =
autd3::Point3::origin(), .rot = autd3::Quaternion::Identity(),}},
autd3::link::Nop{});
autd.send(autd3::Sine(150 * autd3::Hz, autd3::SineOption{}));

const autd3::Point3 center = autd.center() + autd3::Vector3(0., 0., 150.);
while (true) {
  autd.send(
      autd3::Focus{center + autd3::Vector3(20., 0., 0.), autd3::FocusOption{}});

  std::this_thread::sleep_for(std::chrono::milliseconds(1000));

  autd.send(
      autd3::Focus{center - autd3::Vector3(20., 0., 0.), autd3::FocusOption{}});

  std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
using AUTD3Sharp;
using AUTD3Sharp.Utils;
using AUTD3Sharp.Link;
using AUTD3Sharp.Gain;
using AUTD3Sharp.Modulation;
using static AUTD3Sharp.Units;
using var autd = Controller.Open([new AUTD3(pos: Point3.Origin, rot: Quaternion.Identity)], new Nop());
autd.Send(new Sine(
    freq: 150u * Hz,
    option: new SineOption()
));

var center = autd.Center() + new Vector3(0.0f, 0.0f, 150.0f);
while (true)
{
    autd.Send(new Focus(
        pos: center + new Vector3(20.0f, 0.0f, 0.0f),
        option: new FocusOption()
    ));

    Thread.Sleep(1000);

    autd.Send(new Focus(
        pos: center - new Vector3(20.0f, 0.0f, 0.0f),
        option: new FocusOption()
    ));

    Thread.Sleep(1000);
}
import time
import numpy as np
from pyautd3 import AUTD3, Controller, Focus, FocusOption, Hz, Sine, SineOption
from pyautd3.link.nop import Nop
autd = Controller.open([AUTD3(pos=[0.0, 0.0, 0.0], rot=[1, 0, 0, 0])], Nop())
autd.send(
    Sine(
        freq=150 * Hz,
        option=SineOption(),
    )
)

center = autd.center() + np.array([0.0, 0.0, 150.0])
while True:
    autd.send(
        Focus(
            pos=center + np.array([20.0, 0.0, 0.0]),
            option=FocusOption(),
        ),
    )

    time.sleep(1)

    autd.send(
        Focus(
            pos=center - np.array([20.0, 0.0, 0.0]),
            option=FocusOption(),
        ),
    )

    time.sleep(1)

なお, GainModulationは独立しているので, どちらの焦点にもの正弦波AM変調がかかる.

上記のコードだとソフトウェア的にタイミングを制御している. これの精度はOSや実行環境に依存するため, より精度の高い制御が必要な場合は, FociSTM/GainSTMを使用することをおすすめする.

FociSTMを使用して上記と同等の動作を実現するコードは以下の通りである.

use autd3::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut autd = Controller::open([AUTD3::default()], Nop::new())?;
autd.send(Sine {
    freq: 150 * Hz,
    option: SineOption::default(),
})?;

let center = autd.center() + Vector3::new(0.0, 0.0, 150. * mm);
autd.send(FociSTM {
    foci: vec![
        center + Vector3::new(20. * mm, 0.0, 0.0),
        center - Vector3::new(20. * mm, 0.0, 0.0),
    ],
    config: 0.5 * Hz,
    // config: std::time::Duration::from_secs(2),
    // config: SamplingConfig::new(1.0 * Hz),
    // config: SamplingConfig::new(std::time::Duration::from_secs(1)),
})?;
    Ok(())
}
#include <chrono>
#include <vector>
#include "autd3.hpp"
#include "autd3/link/nop.hpp"
int main() {
auto autd = autd3::Controller::open({autd3::AUTD3{.pos =
autd3::Point3::origin(), .rot = autd3::Quaternion::Identity(),}},
autd3::link::Nop{});
autd.send(autd3::Sine(150 * autd3::Hz, autd3::SineOption{}));

const autd3::Point3 center = autd.center() + autd3::Vector3(0., 0., 150.);
autd.send(autd3::FociSTM(
    std::vector{
        center + autd3::Vector3(20., 0., 0.),
        center - autd3::Vector3(20., 0., 0.),
    },
    0.5f * autd3::Hz
    // std::chrono::seconds(2)
    // autd3::SamplingConfig{1.0f * autd3::Hz}
    // autd3::SamplingConfig{std::chrono::seconds(1)}
    ));
return 0;
}
using AUTD3Sharp;
using AUTD3Sharp.Utils;
using AUTD3Sharp.Link;
using AUTD3Sharp.Gain;
using AUTD3Sharp.Modulation;
using static AUTD3Sharp.Units;
using var autd = Controller.Open([new AUTD3(pos: Point3.Origin, rot: Quaternion.Identity)], new Nop());
autd.Send(new Sine(
    freq: 150u * Hz,
    option: new SineOption()
));

var center = autd.Center() + new Vector3(0.0f, 0.0f, 150.0f);
autd.Send(new FociSTM(
    foci: [
        center + new Vector3(20.0f, 0.0f, 0.0f),
        center - new Vector3(20.0f, 0.0f, 0.0f),
    ],
    config: 0.5f * Hz
    // config: Duration.FromSecs(2)
    // config: new SamplingConfig(1.0f * Hz)
    // config: new SamplingConfig(Duration.FromSecs(1))
));
import numpy as np
from pyautd3 import AUTD3, Controller, Hz, Sine, SineOption, FociSTM
from pyautd3.link.nop import Nop
autd = Controller.open([AUTD3(pos=[0.0, 0.0, 0.0], rot=[1, 0, 0, 0])], Nop())
autd.send(
    Sine(
        freq=150 * Hz,
        option=SineOption(),
    )
)

center = autd.center() + np.array([0.0, 0.0, 150.0])
autd.send(
    FociSTM(
        foci=[
            center + np.array([20.0, 0.0, 0.0]),
            center - np.array([20.0, 0.0, 0.0]),
        ],
        config=0.5 * Hz,
        # config=Duration.from_secs(2),
        # config=SamplingConfig(1.0 * Hz),
        # config=SamplingConfig(Duration.from_secs(1)),
    )
)

FociSTM/GainSTMはAUTD3デバイス内部でループされるため, ソフトウェアループは必要なく, FociSTM/GainSTMの送信以降自動的に無限ループする. また, タイミングはAUTD3デバイス内蔵のタイマーで制御されるため, 精度が高く, 解像度も最高で単位で指定できる ただし, このタイマーの制約上, 出力不可能な周波数が存在する.

FociSTM/GainSTMの切り替えタイミングは, 1ループの周波数, または周期で指定する. すなわち, この場合は2つの焦点でとなるので, 各焦点は出力される. なお, SamplingConfigを使用することで, 1ループあたりではなく, サンプリング周波数, すなわち1焦点あたりの周波数や周期を指定することもできる. したがって, 上記のコードのコメントアウト部分はすべて等価である.