MangoTree DAQ Device SDK
Project description
MTDAQ Demo 设计思路与注意事项
环境
| 依赖 | 版本 |
|---|---|
| Python | 3.14.0 |
| numpy | 2.4.4 |
| PyQt5 | 5.15.11 |
| pyqtgraph | 0.14.0 |
| mtdaq | 1.1.0 |
1. 概述
本文档描述MangoTree设备数据采集面板的设计思路,旨在与以下材料配合使用,让生成式 AI 能自主生成不同 MangoTree 设备、不同工作模式的实时采集监控面板:
| 输入材料 | 作用 |
|---|---|
| 本文档 | 设计思路、架构决策、适配方法、常见坑点 |
| X612/AIO.py | 已注释的参考实现 (MT-X612 / General AIO 模式) |
| X612/DI_Trigger_AI.py | 已注释的参考实现 (MT-X612 / DI-Trigger-AI 模式) |
| D814/AIO.py | 已注释的参考实现 (MT-D814 / General AIO 模式) |
| D814/AIO_Sync.py | 已注释的参考实现 (MT-D814 / AOSyncAI 同步模式) |
| D814/DIO.py | 已注释的参考实现 (MT-D814 / General DIO 模式) |
| X610/AIO.py | 已注释的参考实现 (MT-X610 / General AIO 模式) |
| mtdaq 库 | Device API、Mode 枚举、config.txt 配置模板 |
| 设备信息 | 来自 MangoTree 官网 Datasheet/网页的设备规格 (通道数/采样率/类型等) |
技术栈: Python 3, PyQt5, pyqtgraph, numpy, threading.
现有 Demo 清单:
| 目录 | 文件 | 设备 | 模式 | 功能 |
|---|---|---|---|---|
| X612/ | AIO.py | MT-X612 | General (0) | 6 AI + 2 AO + 采样率枚举下拉 |
| X612/ | DI_Trigger_AI.py | MT-X612 | DI-Trigger-AI (5) | 6 AI (触发) + 2 AO |
| D814/ | AIO.py | MT-D814 | General (0) | 16 AI + 4 AO + 独立输入采样率 |
| D814/ | AIO_Sync.py | MT-D814 | AOSyncAI (1) | 16 AI + 4 AO + 同步采样率 (125kHz max) |
| D814/ | DIO.py | MT-D814 | General (0) | 16 DI (指示灯) + 16 DO (翘板开关) |
| D814/ | AIO_Test.py | MT-D814 | General (0) | 16 AI + 4 AO 通道检测 + 分析报告 |
| X610/ | AIO.py | MT-X610 | General (0) | 2 AI + 2 AO + 48k/96k/102.4k/192k/204.8k 采样率 |
文件命名规范:每个 demo 按其功能以大写驼峰命名——
AIO.py(模拟输入/输出)、DIO.py(数字输入/输出)、DI_Trigger_AI.py(DI 触发 AI 采集)。历史聊天记录保留在生成MT-X612 AIO General模式Demo.md中供参考。
1.1 获取设备信息
生成新设备 demo 前,需要从官方渠道获取目标设备的完整规格参数。
官网产品页
| 产品类别 | 官网链接 |
|---|---|
| MT-PXIe 模块 (主页面) | https://www.mangotree.cn/p/19659/ |
| MT-PXIe 模块 (列表页) | https://www.mangotree.cn/p/225128/ |
| APP-PXIe 模块产品 | https://www.mangotree.cn/p/1062267/ |
| APP-PXIe 控制器产品 | https://www.mangotree.cn/p/1062266/ |
| APP-PXIe 机箱产品 | https://www.mangotree.cn/p/1062265/ |
| PXI 机箱、控制器 | https://www.mangotree.cn/app-video/hot.html |
| PCB-RIO | https://www.mangotree.cn/product/659354/ |
Datasheet PDF 目录结构
所有设备 Datasheet PDF 存放在 server.mangotree.cn:9900,按设备类别分层组织:
数据手册/
├── AtomDAQ/ # 一体机 (D814, D815...)
├── AtomRIO/ # Atom RIO 系列
├── E系列采集卡/ # E 系列采集卡
├── PCB-RIO/ # PCB RIO 系列
├── PCIe DAQ模块/ # PCIe DAQ 模块
├── PXIeAll/
│ ├── PXIe-Chassis/ # PXIe 机箱
│ ├── PXIe-Controller/ # PXIe 控制器
│ └── PXIe-Module/
│ ├── DAQ/ # DAQ 模块 (X300~X776, 100+ 型号)
│ ├── RIO/ # FPGA 板卡 (X900~X971)
│ └── Switch/ # 开关模块
├── RobustRIO/ # Robust RIO 系列
├── 产品手册/ # 整体产品手册
└── 雷电模块/ # 雷电接口模块
PDF URL 模式:
# PXIe DAQ 模块
https://server.mangotree.cn:9900/WebFile/Downloads/数据手册/PXIeAll/PXIe-Module/DAQ/{型号}/MT-{型号}%20DataSheet.pdf
# PXIe RIO (FPGA) 模块
https://server.mangotree.cn:9900/WebFile/Downloads/数据手册/PXIeAll/PXIe-Module/RIO/{型号}/MT-{型号}%20DataSheet.pdf
# AtomDAQ 一体机
https://server.mangotree.cn:9900/WebFile/Downloads/数据手册/AtomDAQ/{型号}/MT-{型号}%20DataSheet.pdf
已知 Datasheet 链接:
| 型号 | 类别 | 路径 |
|---|---|---|
| MT-D814 | AtomDAQ 一体机 | AtomDAQ/D814/MT-D814%20DataSheet.pdf |
| MT-D815 | AtomDAQ 一体机 | AtomDAQ/D815/MT-D815%20DataSheet.pdf |
| MT-X590 | 32bit 高精度 8AI | PXIeAll/PXIe-Module/DAQ/X590/ |
| MT-X591 | 32bit 高精度 6AI+2AO | PXIeAll/PXIe-Module/DAQ/X591/ |
| MT-X596 | 32bit 高精度 34AI+4AO | PXIeAll/PXIe-Module/DAQ/X596/ |
| MT-X606 | 热电偶采集 | PXIeAll/PXIe-Module/DAQ/X606/ |
| MT-X610 | 声音振动 2AI+2AO | PXIeAll/PXIe-Module/DAQ/X610/ |
| MT-X612 | 声音振动 6AI+2AO | PXIeAll/PXIe-Module/DAQ/X612/ |
| MT-X613 | 声音振动 4AI+IEPE | PXIeAll/PXIe-Module/DAQ/X613/ |
| MT-X614 | 声音振动 | PXIeAll/PXIe-Module/DAQ/X614/ |
| MT-X900 | FPGA 纯数字 DIO 128ch | PXIeAll/PXIe-Module/RIO/X900/ |
| MT-X920 | FPGA DIO+AI/AO 混合 | PXIeAll/PXIe-Module/RIO/X920/ |
提示:
server.mangotree.cn:9900的目录页可直接浏览, 点击进入子目录即可查看所有型号列表。
PDF 文本提取方法
Datasheet PDF 可通过 pdftotext 或 Python (PyPDF2/pdfplumber) 提取文本:
# 方法1: pdftotext (poppler-utils)
pdftotext -layout MT-X610_DataSheet.pdf output.txt
# 方法2: Python pdfplumber
python -c "import pdfplumber; pdf=pdfplumber.open('MT-X610_DataSheet.pdf'); [print(p.extract_text()) for p in pdf.pages]"
提取后重点查看: 首页标题行 (通道数/分辨率/采样率)、AI/AO 章节的 "Support Sample rate" 行、Idle Channel Noise 表。
第三方信息源
当官网 PDF 无法直接获取时,以下渠道可获取设备规格:
| 来源 | 说明 |
|---|---|
| elecfans.com | 电子发烧友,有 MangoTree 32bit 精度实测系列文章 |
| eepw.com.cn | 电子产品世界,有 MangoTree 新品发布和技术文章 |
| red-hb.com | MangoTree 代理商/合作伙伴,部分产品页有详细规格表 |
| Web Search | 搜索 MT-X{型号} PXIe 规格 采样率 可找到分散在多个平台的产品信息 |
适配 demo 需要提取的关键规格
从 Datasheet/产品页中提取以下信息用于 SAMPLE_RATES、DEFAULT_CONFIG、info_group 和 setup_ui 的填写:
| 参数 | 用途 |
|---|---|
| AI 通道数 | DEFAULT_CONFIG["ai_channels"]、动态曲线数量 |
| AO 通道数 | DEFAULT_CONFIG["ao_channels"]、AO 控件数量 |
| 支持的采样率 | SAMPLE_RATES 字典 |
| 电压范围 | plot_widget.setYRange()、QDoubleSpinBox.setRange() |
| 分辨率 (bit) | info_group 设备信息文本 |
| 耦合方式 | info_group 设备信息文本 |
| 总线类型 (PXIe/USB) | info_group 设备信息文本 |
| 特殊功能 (IEPE/触发等) | info_group 设备信息文本、Config 附加段 |
2. 架构设计
2.1 三层结构
DAQManager (设备管理层)
├── _ai_loop 线程: 循环 dev.analogRead() → 共享缓冲区
├── _ao_loop 线程: 循环生成波形 → dev.analogWrite()
└── _data_version: 单调递增, 标记新数据
MainWindow (UI 层)
├── QTimer(33ms) → update_ui(): 版本号比对, 拷贝新数据
├── _render_latest(): 更新 pyqtgraph 曲线
└── 暂停: 快照 pausing_data, 切换可见性只操作快照
UI 布局 (QSplitter 左右分栏)
├── 左侧: 设备信息/配置/启停/暂停/AO控制
└── 右侧: pyqtgraph 波形图 + 右上角半透明图例浮层
2.2 数据流 (版本号驱动刷新)
_ai_loop 线程:
analogRead(samples) 阻塞等待
→ reshape 为 (samples, channels)
→ lock(_data_lock):
_latest_data = arr.copy()
_data_version += 1
UI 定时器 (33ms 轮询):
if paused: return
if _data_version == _last_data_version: return // 无新数据, 跳过
_last_data_version = version
lock(_data_lock): pending_data = _latest_data.copy()
_render_latest()
为什么不用 Queue: analogRead 在 General 模式下每次阻塞约 1 秒才返回数据,Queue 会让定时器每 33ms 空转检查、暂停时积压数据。版本号方案只在有新数据时才做一次拷贝+渲染。
2.3 暂停/继续机制
暂停: _paused_data = pending_data.copy() // 快照
update_ui 中 if paused: return // 不接触新数据
_render_latest 中 从 _paused_data 读取 // 复选框操作快照
继续: _last_data_version = -1 // 强制下次刷新
_paused_data = empty
_render_latest() // 立即渲染最新数据
2.4 DIO 模式的架构差异
DIO demo 不含 AI/AO,架构更简洁:
DAQManager
├── _di_loop 线程: digitalRead() → uint64 写入共享缓冲区 + 版本号
└── digitalWrite(dodata): 由 UI 线程通过信号直接调用
MainWindow (UI 层)
├── QTimer(33ms) → update_ui(): 版本号比对, 逐 bit 更新 DI 指示灯颜色
├── DO 翘板开关: QPushButton(checkable) → on_do_toggled() → digitalWrite()
└── DI 指示灯: QFrame 圆形, 绿色=1, 灰色=0
关键 API 差异:
digitalRead()返回ctypes.c_uint64,通过.value获取 int,每 bit 对应一个通道digitalWrite(dodata)写入 int,每 bit 对应一个通道,低位先- DI 轮询间隔:
stop_event.wait(0.03)控制 ~33Hz 读取频率 - 无需 Queue 或版本号:DI 数据只有 64bit,直接状态比对
3. Config 配置系统
3.1 配置模板来源
配置模板定义在 mtdaq 库源码目录下的 config.txt 文件中 (与 mtdaq.py 同级)。
所有 MTDAQ 设备通过一个 XML-like 字符串进行配置。关键段:
<Device> <!-- 设备标识: 型号/IP/ID/Slot (ID和Slot可用*) -->
<Advance> <!-- Reset-Device=Auto/Force; Clock-From=Onboard/MT-Chassis -->
<DAQMode> <!-- 工作模式: 0~7 (见 Mode 枚举), Path 仅 Mode=7 有效 -->
<AI> <!-- AI-Channel 通道列表; AI-SampleRate -->
<AO> <!-- AO-Channel 通道列表; AO-SampleRate -->
<DITrigger> <!-- 仅 Mode=4/5/6: DITrigger-Channel/SampleClock/Direction/AIOSamplePerTrigger -->
<TC> <!-- 热电偶: TC-Channel/SampleRate/Type/CJC-Type -->
<RTD> <!-- 热电阻: RTD-Channel/4wire或3wire -->
<DI>/<DO> <!-- 低速数字IO -->
<DigitalWaveformInput> <!-- 高速数字波形输入 -->
<DigitalWaveformOutput> <!-- 高速数字波形输出 -->
<Counter> <!-- 计数器 -->
<PWM> <!-- 脉宽调制 -->
<Encoder> <!-- 编码器 -->
3.2 工作模式 (Mode 枚举)
| DAQMode | 枚举值 | 含义 | 需要的额外配置段 |
|---|---|---|---|
| 0 | General | AI/AO 独立运行 | — |
| 1 | AOSyncAI | AO 同步 AI | — |
| 2 | AISyncEncoder | AI 同步 Encoder | <Encoder> |
| 3 | EncoderSyncAI | Encoder 同步 AI | <Encoder> |
| 4 | DITrigerAISyncAO | DI 触发, AI/AO 同步 | <DITrigger> |
| 5 | DITrigerAI | DI 触发 AI, AO 独立 | <DITrigger> |
| 6 | DITrigerAO | DI 触发 AO | <DITrigger> |
3.3 Config 字符串生成模式
各 demo 中 build_config() 用 Python f-string 模板生成 Config。生成新 demo 时:
- 修改
Device-Model为目标设备型号 (如 X614, X550, X920 等) - 修改
DAQMode为目标工作模式 - 根据模式添加/删除配置段: 如触发模式需添加
<DITrigger>段 - 通道号和采样率 用参数字典占位符
{cfg["key"]}动态替换
3.4 通道范围语法
Config 中通道字段支持 范围写法,用尖括号 <m-n> 表示从 m 到 n(含两端)的所有连续通道号:
| 写法 | 等价展开 |
|---|---|
<0-5> |
0,1,2,3,4,5 |
<0-2>,4 |
0,1,2,4 |
<0-7>,<12-15> |
0,1,2,3,4,5,6,7,12,13,14,15 |
范围与单独通道可混用,仍以逗号 , 分隔。Demo 中通道数较多时(如 D814 的 16 通道),应优先使用范围写法以提高可读性:
"di_channels": "<0-15>" # ✅ 清晰
"di_channels": "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15" # ❌ 冗长
4. DAQManager — 设备管理层的设计
4.1 职责边界
DAQManager 只负责设备和数据,不持有任何 UI 引用。它通过以下接口与 UI 层交互:
| 方向 | 接口 |
|---|---|
| UI → Manager | start() / stop() / update_ao_param() / set_chunk_samples() |
| Manager → UI | running / error / num_channels / num_ao_channels / _data_version / _latest_data |
4.2 AI 采集线程
def _ai_loop(self):
while not self.stop_event.is_set():
data_raw = self.dev.analogRead(samples=samples)
arr = np.ctypeslib.as_array(data_raw) # ctypes → numpy
arr = arr.reshape(samples, self.num_channels)
with self._data_lock:
self._latest_data = arr.copy()
self._data_version += 1
关键点:
analogRead返回 ctypes float 数组,数据交错存储:[ch0_s0, ch1_s0, ch0_s1, ch1_s1, ...]reshape(samples, channels)将其转为便于按列索引的二维数组.copy()必须调用,因为下一次analogRead可能覆写 ctypes 缓冲区_data_version递增告知 UI 有新数据
4.3 AO 输出线程
def _ao_loop(self):
t_base = 0.0 # 全局时间基准, 保证相位连续
while not self.stop_event.is_set():
t = np.linspace(t_base, t_base + CHUNK_SECONDS, samples, endpoint=False)
t_base += CHUNK_SECONDS
for each channel:
wave = amp * sin(2π * freq * t)
full_ao_data[ch_idx::num_channels] = wave # 交错写入
self.dev.analogWrite(full_ao_data.tolist())
关键点:
- 输出格式与输入相同:交错存储
[ch0_s0, ch1_s0, ...] t_base必须跨循环累积,否则每次输出开头会有相位跳变- 通过
ao_lock保护ao_params,UI 线程可安全修改参数
4.4 通道数查询
self.num_channels = self.dev._get_cached_channel_num("AI")
支持查询的通道类型: "AI", "AO", "HSDI", "HSDO", "CI", "CO", "Encoder", "TC"。
4.5 低速数字 I/O (LDI/LDO)
# 读取 DI: 返回 ct.c_uint64, 每 bit 对应一个通道 (低位先)
ldi = self.dev.digitalRead()
di_value = ldi.value # int
# 写入 DO: 传入 int, 每 bit 对应一个通道 (低位先)
self.dev.digitalWrite(do_value)
DI 轮询线程:使用 stop_event.wait(0.03) 替代 time.sleep,可以被 stop_event.set() 立即中断退出。
def _di_loop(self):
while not self.stop_event.is_set():
raw = self.dev.digitalRead()
with self._di_lock:
self._latest_di = raw.value
self._di_version += 1
self.stop_event.wait(0.03) # ~33Hz 轮询
DO 写入:直接由 UI 线程调用,无需后台线程。通过 QPushButton(checkable) 的 clicked 信号触发,更新内部 _do_state 位掩码后调用 digitalWrite。
5. 生成不同设备/模式 Demo 的适配清单
5.1 必须修改的位置
| 位置 | 修改内容 | 示例 |
|---|---|---|
SAMPLE_RATES |
设备支持的采样率 | X550: {"48kHz":48000,"96kHz":96000,"200kHz":200000} |
DEFAULT_CONFIG |
默认 IP/通道/采样率 | 改为目标设备的默认值 |
build_config() |
设备型号和 DAQMode | Device-Model=X550; + DAQMode=5; |
setup_ui() 中 info_group |
设备信息文本 | 型号/模式说明/通道规格 |
__init__ 中的 setWindowTitle |
窗口标题 | "MT-X550 DI-Trigger-AI" |
5.2 按需修改的位置
| 场景 | 修改内容 |
|---|---|
| 触发模式 (Mode=4/5/6) | build_config() 添加 <DITrigger> 段;_ai_loop 中 analogRead 行为变为阻塞等待触发 |
| 无 AO 的设备 | DAQManager 中 num_ao_channels 为 0 时自动隐藏 AO 控件,无需额外处理 |
| 通道数不同的设备 | 无需修改代码,setup_curves() 根据实际通道数动态创建 |
| 其他 I/O 类型 (计数器/编码器/DIO) | 1) build_config() 添加对应段 2) DAQManager 新增采集线程 3) UI 新增控制面板 |
| DIO 专用 (DI+DO) | 1) build_config() 不需要 <AI>/<AO> 2) 参考 D814/DIO.py 的 DI 轮询 + DO 翘板开关模式 3) UI 用 QGridLayout 排列指示灯和开关 |
| 不同电压范围 | 修改 plot_widget.setYRange() 和 QDoubleSpinBox.setRange() |
| 采样率输入方式 | X61 系列 (声音振动): 采样率为固定枚举值, 用 QComboBox 下拉框; 其余设备: 采样率可自由输入, 用 QLineEdit 输入框. 不要使用预设按钮 |
5.3 触发模式注意事项
- Mode=5 (DITrigerAI):
analogRead阻塞等待 DI 触发,触发后一次性返回指定采样点 <DITrigger>段字段名严格遵循 config.txt:DITrigger-Channel=0;DITrigger-SampleClock=500000Hz;(触发检测时钟,最大 1MHz)DITrigger-Direction=0;(0=RisingEdge, 1=FallingEdge, 2=EitherEdge)DITrigger-AIOSamplePerTrigger=-1;(-1=连续采样, N=每次触发采N点)
- 触发模式下
_data_version更新频率取决于触发频率,定时器需保持轮询
6. PyQt5 UI 设计要点
6.1 布局结构
QSplitter(Qt.Horizontal)左右分栏,stretch 比例 1:4- 左侧控制面板用
QVBoxLayout垂直排列各控件组 - 右侧图表用
QVBoxLayout填满 pyqtgraph PlotWidget
6.2 图例浮层
图例面板是 QFrame,parent 设为 plot_container 而非 plot_widget。原因:PlotWidget 内部的 ViewBox 有坐标变换,子控件的绝对定位会受影响。使用外层容器配合 move(x, y) 精确定位。
self.legend_panel = QFrame(plot_container) # 非 plot_widget
self.legend_panel.move(x, y) # 绝对定位到右上角
编辑框宽度自适应:通过 QFontMetrics.horizontalAdvance() 计算所有编辑框中最长文本的像素宽度,统一设置;文字变化时通过 textChanged 信号自动重新同步。
6.3 启动/停止时的 UI 状态管理
| 状态 | 配置控件 | 启动按钮 | 停止按钮 | 暂停按钮 | 定时器 | 曲线 |
|---|---|---|---|---|---|---|
| 初始 | enabled | enabled | disabled | disabled | 停止 | 无 |
| 运行中 | disabled | disabled | enabled | enabled | 运行 | 动态创建 |
| 已停止 | enabled | enabled | disabled | disabled | 停止 | 已清除 |
暂停按钮仅在运行中可用。文本在"暂停"/"继续"之间切换。
6.4 AO 控件闭包
def make_update(idx, a=amp_spin, f=freq_spin):
def update():
if self.manager:
self.manager.update_ao_param(idx, a.value(), f.value())
return update
update_fn = make_update(i)
amp_spin.editingFinished.connect(update_fn)
为什么用闭包而不是 lambda: Python 的 lambda 在循环中会产生延迟求值问题——所有 lambda 会捕获同一个变量 i,最终都是循环终止时的值。闭包通过默认参数 a=amp_spin, f=freq_spin 在定义时绑定当前值。
6.5 DIO 控件设计
DI 指示灯: QFrame 固定尺寸 (14×14px),圆角样式 (border-radius: 6px)。绿色 (#00ff00) 表示高电平,深灰 (#333333) 表示低电平。
DO 翘板开关: QPushButton(checkable=True) 配合样式表模拟翘板开关。checked 伪状态切换背景色:未选中深灰 (#444),选中绿色 (#228B22)。
btn = QPushButton()
btn.setCheckable(True)
btn.setFixedSize(48, 24)
btn.setStyleSheet("""
QPushButton { background-color: #444; border: 1px solid #777; border-radius: 10px; }
QPushButton:checked { background-color: #228B22; border: 1px solid #00ff00; }
""")
# 闭包捕获通道索引, 避免循环变量延迟求值
btn.clicked.connect(lambda checked, c=ch: self.on_do_toggled(c))
位掩码管理: DO 状态用一个 _do_state int 表示,on_do_toggled(ch) 通过 bit = 1 << ch 翻转对应位后调用 digitalWrite(_do_state)。
布局: DI/DO 各 16 通道用 QGridLayout 排列,每行 8 列(每个通道占 2 列:控件+标签)。
7. 关键约束与注意事项
7.1 线程安全
| 资源 | 保护方式 |
|---|---|
_latest_data + _data_version |
threading.Lock() (_data_lock) |
ao_params |
threading.Lock() (ao_lock) |
| Qt 控件 | 只能主线程访问 (通过信号/槽和 QTimer) |
禁止在后台线程直接操作 Qt 控件。后台线程只更新 DAQManager 的数据字段,UI 线程通过 QTimer 回调读取。
7.2 设备生命周期
mtdaq.Device(config_str)— 创建但不启动dev.start()— 调用 DLLMTDAQ_Start,获取设备引用dev.close()— 调用 DLLMTDAQ_Close,释放设备- 必须在
start()后调用_get_cached_channel_num()才能获取通道数 close()在stop()中调用,stop()需等待线程退出后再 close
7.3 资源清理
closeEvent中必须调用stop_device()stop_device()的清理顺序:manager.stop()→timer.stop()→clear_curves()clear_curves()中: 移除 pyqtgraph items → clear 列表 → 递归清空布局 → 调用deleteLater()_clear_layout是递归的: 子布局也需要递归清空
7.4 numpy 内存
- ctypes 数组通过
np.ctypeslib.as_array()创建的是视图 (view),需.copy()确保独立所有权 pending_data和_latest_data是独立的 numpy 数组,不会互扰
7.5 采样率与采样点数的联动
- 切换采样率时 (QComboBox currentTextChanged) → 同步更新
chunk_spin的值 - 修改采样点数时 (QSpinBox valueChanged) → 运行时通过
set_chunk_samples()同步到 DAQManager blockSignals(True/False)防止修改 spinbox 值时再次触发 valueChanged
7.6 设备 IP 和 ID/Slot 通配符
Device-ID=*和Device-Slot=*使用通配符匹配任意设备- 只有在多设备环境需要区分时才需指定具体 ID/Slot
7.7 DIO 注意事项
digitalRead()返回ctypes.c_uint64,不是 int,需通过.value获取 Python int- DI 轮询用
stop_event.wait(0.03)而非time.sleep,可立即响应停止信号 - DO 的
digitalWrite()无需后台线程,UI 线程直接调用是安全的 - 位掩码翻转:
_do_state ^= (1 << ch)或if _do_state & bit: clear else: set
8. 文件结构速查
8.1 X612/AIO.py (General AIO)
行 1-37 文件头注释 (架构概述 / Config 结构 / 适配方法)
行 39-48 import
行 50-60 可配置常量 (SAMPLE_RATES, DEFAULT_CONFIG)
行 70-101 build_config() — Config 字符串生成
行 110-260 class DAQManager — 设备管理层
行 270-890 class MainWindow — UI 层
行 304-326 配置相关
行 328-342 UI 控件回调
行 344-411 启停/暂停
行 413-427 UI 辅助
行 429-588 曲线与图例管理
行 590-768 UI 构建
行 770-810 图例面板辅助
行 812-882 数据刷新与渲染
行 890-897 入口
8.2 D814/DIO.py (General DIO)
行 1-37 文件头注释 (架构概述 / 设备规格)
行 39-47 import
行 50-58 可配置常量 (DI_COUNT, DO_COUNT, DEFAULT_CONFIG)
行 60-85 build_config() — 仅 <DI> + <DO> 段
行 88-135 class DAQManager — DI 轮询 + DO 直写
行 138-310 class MainWindow — UI 层
行 138-160 __init__ / get_config / set_config_fields_enabled
行 162-185 启停 (start_device, stop_device)
行 187-194 on_do_toggled (位掩码翻转)
行 196-215 update_ui + _render_di (指示灯刷新)
行 217-240 控件工厂 (_make_di_indicator, _make_do_toggle)
行 242-305 setup_ui (QGridLayout DI+DO)
行 307-310 closeEvent
行 313-318 入口
8.3 D814/AIO.py (General AIO, 自由采样率)
行 1-53 文件头注释 (架构概述 / 设备规格 / Config 结构 / 适配方法)
行 55-62 import
行 64-70 可配置常量 (DEFAULT_AI_SR, DEFAULT_AO_SR, DEFAULT_CONFIG)
行 72-95 build_config() + _parse_sr()
行 97-215 class DAQManager — AI 循环 + AO 循环, 版本号驱动
行 217-713 class MainWindow — UI 层
行 220-240 __init__ / get_config / set_config_fields_enabled
行 242-260 启停/暂停 (start_device, stop_device, toggle_pause)
行 262-275 曲线清理 (clear_curves, _clear_layout)
行 277-328 setup_curves — 动态曲线 + 图例浮层
行 330-370 setup_ao_controls — AO 幅值/频率控件
行 372-660 setup_ui — 完整 UI 构建 (左右分栏)
行 662-680 图例自适应 (_sync_edit_widths, _update_legend_pos)
行 682-710 数据刷新与渲染 (update_ui, _render_latest)
8.4 D814/AIO_Sync.py (AOSyncAI, 同步采样率)
行 1-28 文件头注释 (设备规格 / 同步模式说明 / 架构概述)
行 30-38 import
行 42-49 可配置常量 (DEFAULT_SYNC_SR, DEFAULT_CONFIG)
行 53-76 build_config() — DAQMode=1, AI/AO 共用 sync_sample_rate
行 78-84 _parse_sr() — 采样率字符串解析
行 88-185 class DAQManager — _sync_sr 统一驱动 AI 和 AO
行 96-98 __init__ 接收 sync_sr 而非 ai_sr, ao_sr
行 141-157 _ai_loop: analogRead 采集
行 159-179 _ao_loop: 使用 _sync_sr 计算 chunk 时长
行 189-440 class MainWindow — UI 层
行 209-219 get_config / set_config_fields_enabled
行 223-233 on_sync_sr_changed — 同步采样点数默认值
行 237-265 启停/暂停
行 278-326 setup_curves — 动态曲线 + 图例浮层
行 328-368 setup_ao_controls — AO 幅值/频率控件
行 372-530 setup_ui — QLineEdit 输入同步采样率 (无预设按钮)
行 547-566 数据刷新与渲染 — 使用 _sync_sr 计算 X 轴时间
与 D814/AIO.py (General) 的关键差异:
DAQMode=1替代DAQMode=0- 单个
sync_sample_rate(QLineEdit) 替代独立的ai_sample_rate/ao_sample_rate DAQManager.__init__接收sync_sr而非ai_sr, ao_sr_ao_loop使用_sync_sr计算 chunk 时长_render_latest使用_sync_sr计算 X 轴时间- 硬件层面 AO 生成主时钟, AI 相位锁定跟随; Python API 调用方式不变
8.5 X612/DI_Trigger_AI.py (DI-Trigger-AI)
行 1-47 CONFIG 静态配置 (DITrigger 段含触发通道/时钟/方向/每次采样数)
行 49-51 常量 (SAMPLE_RATE, TRIGGER_SAMPLES, PLOT_SECONDS)
行 54-70 class DAQManager — Queue 驱动模式, trigger_count 计数器
行 62-70 _ai_loop: analogRead 阻塞等待 DI 上升沿触发
行 73-405 class MainWindow — UI 层
行 73-100 __init__ / 数据初始化
行 102-180 setup_ui — 设备信息/配置/启停/参数控件
行 182-395 setup_curves_dynamic — 启动后动态创建图表+图例+AO
行 397-405 _render_checked / closeEvent
9. 配置模板速查 (config.txt 节选)
以下字段名必须严格匹配,大小写敏感:
<DITrigger>
DITrigger-Channel=0;
DITrigger-SampleClock=500000Hz; // 最大 1MHz
DITrigger-Direction=0; // 0:Rising 1:Falling 2:Either
DITrigger-AIOSamplePerTrigger=-1; // -1:连续 N:每次触发采N点
</DITrigger>
<Counter>
Counter-Channel=0;
Counter-Direction=0; // 0:RisingEdge 1:FallingEdge
Counter-SampleRate=1000Hz;
Counter-PusleSamples=10;
</Counter>
<PWM>
PWM-Channel=0;
PWM-Frequency=1000Hz;
PWM-DutyCycle=50%;
</PWM>
<Encoder>
Encoder-Channel=0;
Encoder-SampleRate=1000Hz;
Encoder-Resolution=2000P/R; // 每圈脉冲数
</Encoder>
<TC>
TC-Channel=0;
TC-SampleRate=20Hz;
TC-Type=K; // B/E/J/K/N/R/S/T
TC-CJC-Type=0; // 0:Internal 1:External
</TC>
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mtdaq-1.1.1-py3-none-any.whl.
File metadata
- Download URL: mtdaq-1.1.1-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09b7c2eece8f11a46950bcd19d3e9028c39a6e64c17b7a74ecdf67a3b11a8884
|
|
| MD5 |
f7a185fd38ea0bdad39e07708d472f64
|
|
| BLAKE2b-256 |
171c0363a7446d59de3644e956427fc84314385c14e2826313b381a09f752026
|