#devices #ni #experiment #streaming #behavior #instrument #national

bin+lib niexpctrl_backend

nicompiler_backend 的扩展,用于在 National Instrument (NI) 设备上定义流行为

1 个不稳定版本

0.1.0 2023 年 9 月 7 日

#11 in #ni

MIT 许可证

51KB
549

niexpctrl_backend - NI 实验控制和流

niexpctrl_backend 提供了一个无缝的接口来控制和流式传输涉及 National Instruments (NI) 设备的实验。它扩展了 nicompiler_backend 遗留库的基本功能,以定义与 NI 硬件交互的行为,同时为用户提供优化和友好的界面。

核心功能

  • NI 设备流和控:使用 experiment 模块,用户可以访问来自 nicompiler_backend 的改进版本的 Experiment 结构,该结构集成了 NI 特定的功能,使可以直接流式传输到 NI 设备及其重置。

  • NI-DAQmx 特定操作nidaqmx 模块提供了一套功能,用于与 NI-DAQmx C 库接口,将 Rust 调用转换为 NI-DAQmx 特定任务。

  • 工具和辅助函数utils 模块提供了额外的工具和辅助函数。

nicompiler_backend 的集成

此包旨在成为 nicompiler_backend 的自然扩展。主要的 Experiment 结构体依赖于并扩展了 nicompiler_backend 中的对应结构体,保持了一般的实验行为,并引入了特定于 NI 设备管理的额外方法。 请参阅 nicompiler_backend 以获取与 NI 流行为无关的通用实现

如何开始

  • 实验设计和控制experiment 模块提供了如何并发流式传输设备任务的实现。

  • 设备管理device 模块实现了流式传输和同步行为。

  • NI-DAQmx 操作nidaqmx 模块提供了调用 NI-DAQmx C 库的 Rust 包装方法,以实现无缝的 NI 设备操作。

  • 工具:有关通用工具和辅助功能,请探索 utils 模块。

带有流式传输的示例用法

Rust

回想一下之前在 nicompiler_backend 中的相同示例代码片段。

我们在设计并编译实验后,额外调用了 exp.stream_exp((50., 2)); 以通过50毫秒的流缓冲区和两次重复来流式传输实验。有关流行为的更多信息,请参阅 StreamableDevice::stream_task

use niexpctrl_backend::*;
let mut exp = Experiment::new();
// Define devices and associated channels
exp.add_ao_device("PXI1Slot3", 1e6);
exp.add_ao_channel("PXI1Slot3", 0);

exp.add_ao_device("PXI1Slot4", 1e6);
exp.add_ao_channel("PXI1Slot4", 0);

exp.add_do_device("PXI1Slot6", 1e7);
exp.add_do_channel("PXI1Slot6", 0, 0);
exp.add_do_channel("PXI1Slot6", 0, 4);

// Define synchronization behavior:
exp.device_cfg_trig("PXI1Slot3", "PXI1_Trig0", true);
exp.device_cfg_ref_clk("PXI1Slot3", "PXI1_Trig7", 1e7, true);

exp.device_cfg_trig("PXI1Slot4", "PXI1_Trig0", false);
exp.device_cfg_ref_clk("PXI1Slot4", "PXI1_Trig7", 1e7, false);

exp.device_cfg_samp_clk_src("PXI1Slot6", "PXI1_Trig7");
exp.device_cfg_trig("PXI1Slot6", "PXI1_Trig0", false);

// PXI1Slot3/ao0 starts with a 1s-long 7Hz sine wave with offset 1
// and unit amplitude, zero phase. Does not keep its value.
exp.sine("PXI1Slot3", "ao0", 0., 1., false, 7., None, None, Some(1.));
// Ends with a half-second long 1V constant signal which returns to zero
exp.constant("PXI1Slot3", "ao0", 9., 0.5, 1., false);

// We can also leave a defined channel empty: the device / channel will simply not be compiled

// Both lines of PXI1Slot6 start with a one-second "high" at t=0 and a half-second high at t=9
exp.high("PXI1Slot6", "port0/line0", 0., 1.);
exp.high("PXI1Slot6", "port0/line0", 9., 0.5);
// Alternatively, we can also define the same behavior via go_high/go_low
exp.go_high("PXI1Slot6", "port0/line4", 0.);
exp.go_low("PXI1Slot6", "port0/line4", 1.);

exp.go_high("PXI1Slot6", "port0/line4", 9.);
exp.go_low("PXI1Slot6", "port0/line4", 9.5);

exp.compile_with_stoptime(10.); // Experiment signal will stop at t=10 now
assert_eq!(exp.compiled_stop_time(), 10.);

exp.stream_exp(50., 2);

Python

功能上与上述代码相同,此外还采样并绘制了 PXI1Slot6/port0/line4 的信号。 Experiment 对象的主要目标是提供一组完整的快速 Rust 实现的接口方法,用于与 NI 实验进行交互。可以通过在 Python 代码中包装 nicompiler_backend 模块来轻松自定义语法糖和高级抽象,请参阅我们的 项目页面 以查看此类示例之一。

# Instantiate experiment, define devices and channels
from nicompiler_backend import Experiment
import matplotlib.pyplot as plt

exp = Experiment()
exp.add_ao_device(name="PXI1Slot3", samp_rate=1e6)
exp.add_ao_channel(name="PXI1Slot3", channel_id=0)

...

# Define synchronization behavior
exp.device_cfg_trig(name="PXI1Slot3", trig_line="PXI1_Trig0", export_trig=True)
exp.device_cfg_ref_clk(name="PXI1Slot3", ref_clk_line="PXI1_Trig7",
                       ref_clk_rate=1e7, export_ref_clk=True)
...

# Define signal
# Arguments of "option" type in rust is converted to optional arguments in python
exp.sine(dev_name="PXI1Slot3", chan_name="ao0", t=0., duration=1., keep_val=False,
         freq=7., dc_offset=1.)
...

exp.compile_with_stoptime(10.)
exp.stream_exp(50., 2)

依赖关系

~9–16MB
~207K SLoC