Emulator
Emulator は, 実機なしで AUTD3 の出力データを記録し, そこから音場をオフライン計算するツールである (C# には提供していない).
Emulator::new に Geometry を渡し, 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(())})?;emulator = Emulator(geometry)
def record_fn(r: Recorder) -> None: builder = r.datagram_builder() builder.push(Pattern(patterns)) for frame in builder.build(): r.send_checked(frame) r.tick(Duration.from_millis(1))
record = emulator.record(record_fn)tick に渡す時間は超音波周期 ( 25 us ) の整数倍でなければならない.
出力データは Polars の DataFrame である.
詳細は Polars のドキュメントを参照されたい.
振動子テーブル
Section titled “振動子テーブル”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);table = emulator.transducer_table()print(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 │└─────────┴────────┴────────────┴────────────┴───────┴─────┴─────┴─────┘出力データの取得
Section titled “出力データの取得”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);phase = record.phase()print(phase)
pulse_width = record.pulse_width()print(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 │└───────────────────┴───────────────────────┴───────────────────────┴───────────────────────┴───┴────────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┘出力信号の取得
Section titled “出力信号の取得”振動子に印加される電圧と, 振動子からの出力超音波をBVD (Butterworth-Van Dyke) モデルで計算する. いずれも時間分解能は 25 us / 512 である.
let voltage = record.output_voltage();dbg!(voltage);
let ultrasound = record.output_ultrasound();dbg!(ultrasound);voltage = record.output_voltage()print(voltage)
ultrasound = record.output_ultrasound()print(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);rms = record.sound_field(rng, RmsRecordOption())observe_points = rms.observe_points()print(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 │└────────────┴───────────┴───────┘RMS 音圧
Section titled “RMS 音圧”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);rng = RangeXY( x=(target[0] - 20.0, target[0] + 20.0), y=(target[1] - 20.0, target[1] + 20.0), z=float(target[2]), resolution=1.0,)rms = record.sound_field(rng, RmsRecordOption())field = rms.next(Duration.from_micros(25))print(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);instant = record.sound_field( rng, InstantRecordOption(time_step=Duration.from_micros(1)),)instant.skip(Duration.from_micros(500))field = instant.next(Duration.from_micros(25))print(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 等がある.
軸の順序 ( RangeXY と RangeYX 等 ) は観測点の列挙順を決める.
resolution は各軸の刻み幅 ( mm ) である.
GPU バックエンド (Rust 版のみ)
Section titled “GPU バックエンド (Rust 版のみ)”gpu feature を有効にすると, 音場計算を GPU で行える.
有効時のみ各オプションに gpu: bool フィールドが生え, true で GPU を使う ( 既定は false ).
let mut rms = record.sound_field( range, RmsRecordOption { gpu: true, ..Default::default() },)?;