コンテンツにスキップ

Emulator

Emulator は, 実機なしで AUTD3 の出力データを記録し, そこから音場をオフライン計算するツールである (C# には提供していない).

Emulator::newGeometry を渡し, record 内部でデータを送信し, tick で時間を進めると, 送信データが記録された Record が得られる.

let emulator = Emulator::new(geometry);
let record = emulator.record(async move |r| {
let mut builder = r.datagram_builder();
builder.push(Pattern::new(&patterns));
let datagrams = builder.build()?;
for frame in &datagrams {
r.send_checked(frame).await?;
}
r.tick(Duration::from_millis(1))?;
Ok(())
})?;

tick に渡す時間は超音波周期 ( 25 us ) の整数倍でなければならない.

出力データは PolarsDataFrame である. 詳細は Polars のドキュメントを参照されたい.

Emulator::transducer_table は, 全トランスデューサの一覧を DataFrame として返す. 各行が 1 トランスデューサで, デバイスインデックス ( dev_idx ), デバイス内のローカルインデックス ( tr_idx ), 位置 ( x/y/z[mm] ), 法線方向 ( nx/ny/nz ) が格納される. 後述の出力データ・出力信号の各行は, このテーブルの行と 1 対 1 で対応している.

let table = emulator.transducer_table();
dbg!(table);
shape: (249, 8)
┌─────────┬────────┬────────────┬────────────┬───────┬─────┬─────┬─────┐
│ dev_idx ┆ tr_idx ┆ x[mm] ┆ y[mm] ┆ z[mm] ┆ nx ┆ ny ┆ nz │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ u16 ┆ u8 ┆ f32 ┆ f32 ┆ f32 ┆ f32 ┆ f32 ┆ f32 │
╞═════════╪════════╪════════════╪════════════╪═══════╪═════╪═════╪═════╡
│ 0 ┆ 0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 1 ┆ 10.16 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 2 ┆ 20.32 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 3 ┆ 30.48 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 4 ┆ 40.639999 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 0 ┆ 244 ┆ 132.080002 ┆ 132.080002 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 245 ┆ 142.23999 ┆ 132.080002 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 246 ┆ 152.399994 ┆ 132.080002 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 247 ┆ 162.559998 ┆ 132.080002 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
│ 0 ┆ 248 ┆ 172.720001 ┆ 132.080002 ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 1.0 │
└─────────┴────────┴────────────┴────────────┴───────┴─────┴─────┴─────┘

record が返す Record から, 記録された出力データを取得できる. phase / pulse_width は列が時刻の DataFrame を返す. 列名は phase@<時刻>[ns] / pulse_width@<時刻>[ns] で, 時刻は超音波周期 ( 25 us ) 刻みである.

let phase = record.phase();
dbg!(phase);
let pulse_width = record.pulse_width();
dbg!(pulse_width);
shape: (249, 40)
┌─────────────┬─────────────────┬─────────────────┬─────────────────┬───┬──────────────────┬──────────────────┬──────────────────┬──────────────────┐
│ phase@0[ns] ┆ phase@25000[ns] ┆ phase@50000[ns] ┆ phase@75000[ns] ┆ … ┆ phase@900000[ns] ┆ phase@925000[ns] ┆ phase@950000[ns] ┆ phase@975000[ns] │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ u8 ┆ u8 ┆ u8 ┆ u8 ┆ ┆ u8 ┆ u8 ┆ u8 ┆ u8 │
╞═════════════╪═════════════════╪═════════════════╪═════════════════╪═══╪══════════════════╪══════════════════╪══════════════════╪══════════════════╡
│ 1 ┆ 2 ┆ 3 ┆ 4 ┆ … ┆ 38 ┆ 39 ┆ 40 ┆ 42 │
│ 254 ┆ 252 ┆ 250 ┆ 248 ┆ … ┆ 183 ┆ 181 ┆ 179 ┆ 178 │
│ 1 ┆ 2 ┆ 3 ┆ 4 ┆ … ┆ 40 ┆ 41 ┆ 42 ┆ 44 │
│ 253 ┆ 250 ┆ 248 ┆ 245 ┆ … ┆ 158 ┆ 156 ┆ 153 ┆ 151 │
│ 255 ┆ 255 ┆ 254 ┆ 254 ┆ … ┆ 242 ┆ 241 ┆ 241 ┆ 241 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 0 ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ 4 ┆ 4 ┆ 4 ┆ 5 │
│ 253 ┆ 251 ┆ 249 ┆ 247 ┆ … ┆ 177 ┆ 175 ┆ 173 ┆ 171 │
│ 1 ┆ 3 ┆ 4 ┆ 6 ┆ … ┆ 60 ┆ 61 ┆ 63 ┆ 65 │
│ 254 ┆ 253 ┆ 251 ┆ 250 ┆ … ┆ 203 ┆ 201 ┆ 200 ┆ 199 │
│ 1 ┆ 3 ┆ 4 ┆ 6 ┆ … ┆ 58 ┆ 59 ┆ 61 ┆ 63 │
└─────────────┴─────────────────┴─────────────────┴─────────────────┴───┴──────────────────┴──────────────────┴──────────────────┴──────────────────┘
shape: (249, 40)
┌───────────────────┬───────────────────────┬───────────────────────┬───────────────────────┬───┬────────────────────────┬────────────────────────┬────────────────────────┬────────────────────────┐
│ pulse_width@0[ns] ┆ pulse_width@25000[ns] ┆ pulse_width@50000[ns] ┆ pulse_width@75000[ns] ┆ … ┆ pulse_width@900000[ns] ┆ pulse_width@925000[ns] ┆ pulse_width@950000[ns] ┆ pulse_width@975000[ns] │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ u16 ┆ u16 ┆ u16 ┆ u16 ┆ ┆ u16 ┆ u16 ┆ u16 ┆ u16 │
╞═══════════════════╪═══════════════════════╪═══════════════════════╪═══════════════════════╪═══╪════════════════════════╪════════════════════════╪════════════════════════╪════════════════════════╡
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
│ 16 ┆ 33 ┆ 49 ┆ 67 ┆ … ┆ 256 ┆ 256 ┆ 256 ┆ 256 │
└───────────────────┴───────────────────────┴───────────────────────┴───────────────────────┴───┴────────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┘

振動子に印加される電圧と, 振動子からの出力超音波をBVD (Butterworth-Van Dyke) モデルで計算する. いずれも時間分解能は 25 us / 512 である.

let voltage = record.output_voltage();
dbg!(voltage);
let ultrasound = record.output_ultrasound();
dbg!(ultrasound);
shape: (249, 20_480)
┌────────────────────────┬────────────────────────┬────────────────────────┬────────────────────────┬───┬────────────────────────────┬────────────────────────────┬────────────────────────────┬────────────────────────────┐
│ voltage[V]@0[25us/512] ┆ voltage[V]@1[25us/512] ┆ voltage[V]@2[25us/512] ┆ voltage[V]@3[25us/512] ┆ … ┆ voltage[V]@20476[25us/512] ┆ voltage[V]@20477[25us/512] ┆ voltage[V]@20478[25us/512] ┆ voltage[V]@20479[25us/512] │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ f32 ┆ f32 ┆ f32 ┆ f32 ┆ ┆ f32 ┆ f32 ┆ f32 ┆ f32 │
╞════════════════════════╪════════════════════════╪════════════════════════╪════════════════════════╪═══╪════════════════════════════╪════════════════════════════╪════════════════════════════╪════════════════════════════╡
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ -12.0 ┆ -12.0 ┆ -12.0 ┆ -12.0 │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 │
│ 12.0 ┆ 12.0 ┆ -12.0 ┆ -12.0 ┆ … ┆ -12.0 ┆ -12.0 ┆ -12.0 ┆ -12.0 │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 │
│ 12.0 ┆ 12.0 ┆ -12.0 ┆ -12.0 ┆ … ┆ -12.0 ┆ -12.0 ┆ -12.0 ┆ -12.0 │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ -12.0 ┆ -12.0 ┆ -12.0 ┆ -12.0 │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 │
│ 12.0 ┆ 12.0 ┆ 12.0 ┆ 12.0 ┆ … ┆ -12.0 ┆ -12.0 ┆ 12.0 ┆ 12.0 │
└────────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┴───┴────────────────────────────┴────────────────────────────┴────────────────────────────┴────────────────────────────┘
shape: (249, 20_480)
┌─────────────────────┬─────────────────────┬─────────────────────┬─────────────────────┬───┬─────────────────────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┐
│ p[a.u.]@0[25us/512] ┆ p[a.u.]@1[25us/512] ┆ p[a.u.]@2[25us/512] ┆ p[a.u.]@3[25us/512] ┆ … ┆ p[a.u.]@20476[25us/512] ┆ p[a.u.]@20477[25us/512] ┆ p[a.u.]@20478[25us/512] ┆ p[a.u.]@20479[25us/512] │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ f32 ┆ f32 ┆ f32 ┆ f32 ┆ ┆ f32 ┆ f32 ┆ f32 ┆ f32 │
╞═════════════════════╪═════════════════════╪═════════════════════╪═════════════════════╪═══╪═════════════════════════╪═════════════════════════╪═════════════════════════╪═════════════════════════╡
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ 0.367795 ┆ 0.379597 ┆ 0.391337 ┆ 0.403013 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ 0.261409 ┆ 0.250499 ┆ 0.239553 ┆ 0.228573 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ 0.325682 ┆ 0.337693 ┆ 0.349649 ┆ 0.361547 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000766 ┆ … ┆ -0.237067 ┆ -0.247149 ┆ -0.257188 ┆ -0.267184 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ 0.980448 ┆ 0.98075 ┆ 0.980904 ┆ 0.980913 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ 0.904004 ┆ 0.909175 ┆ 0.914209 ┆ 0.919103 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000766 ┆ … ┆ 0.13367 ┆ 0.122602 ┆ 0.111521 ┆ 0.100428 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ -0.108901 ┆ -0.096903 ┆ -0.084897 ┆ -0.072884 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ 0.620835 ┆ 0.612537 ┆ 0.604152 ┆ 0.595681 │
│ 0.0 ┆ -0.000272 ┆ -0.000481 ┆ -0.000618 ┆ … ┆ -0.066326 ┆ -0.054301 ┆ -0.042275 ┆ -0.0301 │
└─────────────────────┴─────────────────────┴─────────────────────┴─────────────────────┴───┴─────────────────────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┘

Record::sound_field に観測範囲 ( Range ) とオプションを渡すと, 音場計算オブジェクトが得られる. オプションには RmsRecordOption ( RMS 音圧 ) と InstantRecordOption ( 瞬時音圧 ) の 2 種類がある.

いずれも observe_points で観測点座標を, next で指定時間分の音場を得られる. skip で計算せずに時間を進められる.

observe_points が返す DataFrame の各行が観測点で, 音場の DataFrame の各行と対応する.

let rms = record.sound_field(range, RmsRecordOption::default())?;
let observe_points = rms.observe_points();
dbg!(observe_points);
shape: (1_681, 3)
┌────────────┬───────────┬───────┐
│ x[mm] ┆ y[mm] ┆ z[mm] │
│ --- ┆ --- ┆ --- │
│ f32 ┆ f32 ┆ f32 │
╞════════════╪═══════════╪═══════╡
│ 66.625267 ┆ 46.713196 ┆ 150.0 │
│ 67.625267 ┆ 46.713196 ┆ 150.0 │
│ 68.625267 ┆ 46.713196 ┆ 150.0 │
│ 69.625267 ┆ 46.713196 ┆ 150.0 │
│ 70.625267 ┆ 46.713196 ┆ 150.0 │
│ … ┆ … ┆ … │
│ 102.625267 ┆ 86.713196 ┆ 150.0 │
│ 103.625267 ┆ 86.713196 ┆ 150.0 │
│ 104.625267 ┆ 86.713196 ┆ 150.0 │
│ 105.625267 ┆ 86.713196 ┆ 150.0 │
│ 106.625267 ┆ 86.713196 ┆ 150.0 │
└────────────┴───────────┴───────┘

next が返す DataFrame の各列に, 観測点ごとの RMS 音圧が 25 μs 毎に格納される ( 列名 rms[Pa]@<時刻>[ns] ).

let range = RangeXY {
x: (target.x - 20.0)..=(target.x + 20.0),
y: (target.y - 20.0)..=(target.y + 20.0),
z: target.z,
resolution: 1.0,
};
let mut rms = record.sound_field(range.clone(), RmsRecordOption::default())?;
let field = rms.next(Duration::from_micros(25))?;
dbg!(field);
shape: (1_681, 1)
┌───────────────┐
│ rms[Pa]@0[ns] │
│ --- │
│ f32 │
╞═══════════════╡
│ 22.213818 │
│ 22.964384 │
│ 23.199003 │
│ 22.829695 │
│ 21.915253 │
│ … │
│ 19.375198 │
│ 19.254133 │
│ 18.922194 │
│ 18.434885 │
│ 17.942478 │
└───────────────┘

瞬時音圧は, time_step で時間分解能を指定する. next が返す DataFrame の各列に, 観測点ごとの瞬時音圧が time_step 刻みで格納される ( 列名 p[Pa]@<時刻>[ns] ).

let mut instant = record.sound_field(
range,
InstantRecordOption {
time_step: Duration::from_micros(1),
..Default::default()
},
)?;
instant.skip(Duration::from_micros(500))?;
let field = instant.next(Duration::from_micros(25))?;
dbg!(field);
shape: (1_681, 25)
┌──────────────────┬──────────────────┬──────────────────┬──────────────────┬───┬──────────────────┬──────────────────┬──────────────────┬──────────────────┐
│ p[Pa]@500000[ns] ┆ p[Pa]@501000[ns] ┆ p[Pa]@502000[ns] ┆ p[Pa]@503000[ns] ┆ … ┆ p[Pa]@521000[ns] ┆ p[Pa]@522000[ns] ┆ p[Pa]@523000[ns] ┆ p[Pa]@524000[ns] │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ f32 ┆ f32 ┆ f32 ┆ f32 ┆ ┆ f32 ┆ f32 ┆ f32 ┆ f32 │
╞══════════════════╪══════════════════╪══════════════════╪══════════════════╪═══╪══════════════════╪══════════════════╪══════════════════╪══════════════════╡
│ 10.003653 ┆ 3.894438 ┆ -6.252444 ┆ -16.506908 ┆ … ┆ 28.38765 ┆ 28.567314 ┆ 29.98049 ┆ 32.387314 │
│ 7.126377 ┆ 2.020372 ┆ -8.165694 ┆ -17.129423 ┆ … ┆ 31.707983 ┆ 31.654594 ┆ 30.74332 ┆ 31.946955 │
│ 3.92967 ┆ -1.315457 ┆ -9.487965 ┆ -16.549021 ┆ … ┆ 35.146038 ┆ 35.977501 ┆ 33.133389 ┆ 30.673653 │
│ 0.343901 ┆ -5.408858 ┆ -10.659369 ┆ -15.897531 ┆ … ┆ 38.936932 ┆ 39.213017 ┆ 35.64106 ┆ 29.435026 │
│ -1.625009 ┆ -8.594726 ┆ -11.886508 ┆ -15.217589 ┆ … ┆ 41.400124 ┆ 41.093994 ┆ 36.455021 ┆ 29.054434 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 1.06873 ┆ -4.236325 ┆ -7.555728 ┆ -12.076913 ┆ … ┆ 33.985756 ┆ 36.456608 ┆ 34.53088 ┆ 29.42366 │
│ 4.188988 ┆ -0.0129 ┆ -5.104079 ┆ -12.541022 ┆ … ┆ 30.883274 ┆ 34.034138 ┆ 33.920597 ┆ 29.746302 │
│ 8.367446 ┆ 4.674797 ┆ -3.678846 ┆ -13.309359 ┆ … ┆ 28.576004 ┆ 30.555122 ┆ 31.229137 ┆ 31.220989 │
│ 12.870935 ┆ 7.263134 ┆ -2.312043 ┆ -13.103703 ┆ … ┆ 26.725754 ┆ 27.065441 ┆ 29.68734 ┆ 32.745209 │
│ 15.355244 ┆ 8.761391 ┆ -1.179362 ┆ -12.026244 ┆ … ┆ 24.756136 ┆ 25.81175 ┆ 29.540882 ┆ 33.987869 │
└──────────────────┴──────────────────┴──────────────────┴──────────────────┴───┴──────────────────┴──────────────────┴──────────────────┴──────────────────┘

Range は観測点の集合を表す. RangeXY のような平面のほか, 1 軸のみの RangeX 等, 3 軸すべての RangeXYZ 等がある. 軸の順序 ( RangeXYRangeYX 等 ) は観測点の列挙順を決める. resolution は各軸の刻み幅 ( mm ) である.

gpu feature を有効にすると, 音場計算を GPU で行える. 有効時のみ各オプションに gpu: bool フィールドが生え, true で GPU を使う ( 既定は false ).

let mut rms = record.sound_field(
range,
RmsRecordOption {
gpu: true,
..Default::default()
},
)?;