mcpField
M
matlab-modernize-daq

matlab-modernize-daq

github.com/matlab开发1.2k42 次安装1 天前更新
代码仓库

关于 matlab-modernize-daq

面向 MATLAB 用户的技能,用于迁移旧版 Data Acquisition Toolbox 脚本或编写多功能采集流程。它将基于 session 的调用映射到 R2020a 的 DataAcquisition 接口,并提示回调、触发器和生命周期中的常见问题。

主要功能

  1. 01将 session API 调用映射到 DataAcquisition
  2. 02指导触发器与时钟配置
  3. 03涵盖回调驱动的流式采集
  4. 04讲解输出缓冲与自动补充
  5. 05检查脚本中的常见静默错误

适用场景

  1. 01迁移使用 daq.createSession 的脚本
  2. 02替换旧事件监听器和生命周期调用
  3. 03编写含触发器或回调的流式脚本

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-modernize-daq

安装后在 Claude Code 中输入/matlab-modernize-daq确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

manifest.yaml
references/
callback-state-patterns.md
canonical-snippets.md
session-to-modern-mapping.md
scripts/
verifyDataAcquisition.m

详细介绍

将 DAQ 代码迁移到现代 DataAcquisition 接口

将基于旧版会话的 Data Acquisition Toolbox 代码(daq.createSession、addAnalogInputChannel、DataAvailable 侦听器、startBackground、queueOutputData、wait)迁移到 R2020a 引入的现代 DataAcquisition 接口(daq("ni")、addinput、ScansAvailableFcn、start、write、preload)。也涵盖如何编写新的多功能 DAQ 脚本:在认知负荷较高时,现代 API 模式很容易出错。

适用场景

  • 迁移调用 daq.createSession、addAnalogInputChannel、addAnalogOutputChannel、addCounterInputChannel、addCounterOutputChannel 或 addDigitalChannel 的现有脚本。
  • 将 DataAvailable / DataRequired / ErrorOccurred 侦听器替换为 ScansAvailableFcn / ScansRequiredFcn / ErrorOccurredFcn。
  • 替换 startBackground / startForeground / s.wait() 生命周期调用。
  • 将 queueOutputData 替换为 preload + write。
  • 编写结合以下两项或更多功能的新 DAQ 脚本:外部触发、连续采集、由回调驱动的数据流、带补充数据的模拟输出,或跨回调共享状态。
  • 调试类似 Undefined function 'wait' for input arguments of type 'daq.interfaces.DataAcquisition' 或 Unrecognized method, property, or field 'Data' for class 'matlabshared.asyncio.buffer.ElementsAvailableInfo' 的错误。

不适用场景

  • 不使用触发器或回调的单通道前台采集(例如,“以 10 kHz 从 ai0 采集 1 s 的电压并绘图”)。在这种规模下,现代 API 简单易用,使用此技能会徒增开销。
  • 选择 DAQ 厂商或评估非 NI 硬件。此技能的证据基础是 NI。
  • 对已采集的数据进行信号处理或分析(滤波、频谱分析等)。此技能仅涵盖通过 DataAcquisition 接口采集和生成数据,不涵盖后处理。
  • Simulink、App Designer 或实时目标 DAQ 工作流。
  • 现代化 matlab.unittest 测试套件或框架式测试类(参数化 fixture、assumeTrue 门控、参数数量契约测试、辅助类层次结构)。此技能中的 API 替换方法适用,但测试框架搭建工作(移除父类、重新设计 fixture、废弃针对已移除契约的测试)不在范围内。使用此技能转换测试主体中的 API 调用,然后单独处理测试框架层面的判断。

工作流

迁移基于会话的脚本或编写新的多功能 DAQ 脚本时,请按以下顺序操作。每一步完成后都要验证——此领域的大多数故障模式都不会显现。

  1. 盘点旧版脚本(仅适用于迁移)。 确认设备、通道类型、速率、连续采集还是有限采集、触发器/时钟连接、回调(DataAvailable / DataRequired / ErrorOccurred)、回调间共享的状态,以及输出排队方式。

  2. 转换术语。 将每个会话 API 标记映射到对应的现代 API。请查阅 references/session-to-modern-mapping.md——旧版脚本中出现会话 API 标记时,务必加载此文件。常见的静默改名陷阱:NotifyWhenDataAvailableExceeds → ScansAvailableFcnCount,NumberOfScans / NumScans → 隐式(没有对应参数),ExternalTriggerTimeout → DigitalTriggerTimeout,IsContinuous=true → start(d, "Continuous") 参数。

  3. 构建 DataAcquisition 对象。 使用 d = daq("ni"),设置 d.Rate,并通过 addinput / addoutput 添加通道。通过 addinput / addoutput 返回的通道句柄设置每个通道的属性。

  4. 连接触发器和时钟。 使用 references/canonical-snippets.md §1——脚本涉及 addtrigger 或 addclock 时加载此文件。参数顺序为 (d, type, role, trigSrc, trigDest)——Source 是第 4 个参数,Destination 是第 5 个参数。**验证:**返回的触发器对象的 Source 和 Destination 字段应显示预期值。

  5. 连接回调。 使用规范代码片段 §2 — 当脚本需要 ScansAvailableFcn 或 ScansRequiredFcn 时加载该片段。在回调内,始终通过 read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix") 获取数据 — evt 参数的类型为 matlabshared.asyncio.buffer.ElementsAvailableInfo,仅提供 NumElementsAvailable,不提供 Data 或 TimeStamps。强烈建议连接 d.ErrorOccurredFcn = @(~,evt) fprintf("DAQ error: %s\n", evt.Error.message) — 如果不连接,其他回调中的异常会被静默吞掉,运行也会“成功”,但每次触发都会抛出异常。对于旧脚本没有 ErrorOccurred 侦听器的严格移植,应向用户说明这一权衡,而不是悄悄添加处理程序 — 让用户自行选择是否启用。

  6. 选择一种状态共享模式(仅限回调)。 如果回调需要在多次触发之间维护状态(运行计数器、相位累加器、锁存标志),请参阅 references/callback-state-patterns.md — 只要回调需要维护状态,就加载该文件。默认使用句柄类包装器或嵌套函数。避免使用 src.UserData.X = src.UserData.X + ... 修改字段;这种修改不会保留。

  7. 连接生命周期。 使用规范代码片段 §3 — 等待完成时加载该片段。现代对象没有 wait(d) 方法。对于有限采集,优先使用 start(d, "Duration", seconds(N)),然后调用 read 或轮询 Running。对于连续采集,在回调内设置停止条件(if scansRead >= target; stop(src); end),并在调用方轮询 d.Running。

  8. 实时执行前运行 verifyDataAcquisition。 脚本:scripts/verifyDataAcquisition.m。该脚本通过检查实时对象并搜索源文件,捕获出现频率最高的四种静默缺陷(缺少 ErrorOccurredFcn、回调源代码中使用 evt.Data、wait(d) 令牌、UserData.X = UserData.X + ... 字段修改)。如果有 mcp__matlab__run_matlab_file,请通过它运行;否则,将脚本复制到用户的项目中。

  9. 实时验证。 运行一个较短版本(例如 1–2 s,而不是用户要求的完整时长)。检查脚本是否顺利执行到 start,回调是否至少触发一次,以及 ErrorOccurredFcn 是否没有打印错误。请使用 mcp__matlab__run_matlab_file 运行已保存的 .m 文件,不要使用 mcp__matlab__evaluate_matlab_code — 求值字符串缓冲区以脚本模式运行,会拒绝局部函数或嵌套函数定义,而模式 5 和大多数回调主体都需要这些定义。

关键功能

功能用途工具箱起始版本
daq创建 DataAcquisition 对象(d = daq("ni"))Data Acquisition ToolboxR2020a
addinput添加输入通道(模拟、计数器或数字)Data Acquisition ToolboxR2020a
addoutput添加输出通道Data Acquisition ToolboxR2020a
addtrigger添加触发器连接:addtrigger(d, type, role, trigSrc, trigDest)Data Acquisition ToolboxR2020a
addclock添加时钟连接(签名类似)Data Acquisition ToolboxR2020a
read前台采集,或在 ScansAvailableFcn 中提取数据Data Acquisition ToolboxR2020a
write写入输出样本(也可在 ScansRequiredFcn 中调用)Data Acquisition ToolboxR2020a
preload在 start(d, "Continuous") 之前载入初始输出缓冲区。仅适用于输出通道。Data Acquisition ToolboxR2020a
start开始后台采集:start(d)、start(d, "Continuous")、start(d, "Duration", seconds(N))Data Acquisition ToolboxR2020a
stop停止正在运行的采集Data Acquisition ToolboxR2020a
flush读取前丢弃缓冲的扫描数据Data Acquisition ToolboxR2020a
daqlist枚举可用设备(替代 daq.getDevices)Data Acquisition ToolboxR2020a
daqreset重置 DAQ 子系统(替代 daq.reset)Data Acquisition ToolboxR2020a

DataAcquisition 的属性:Rate、Running、NumScansAcquired、NumScansOutputByHardware、ScansAvailableFcn、ScansAvailableFcnCount、ScansRequiredFcn、ScansRequiredFcnCount、ErrorOccurredFcn、DigitalTriggerTimeout、UserData。

模式

以下五种典型模式的完整内容(含已验证代码)见 references/canonical-snippets.md。下方仅列出每种模式的最简回忆片段,帮助 Agent 在高负载下唤起记忆。需要完整、可运行的形式时,请加载参考文件。

模式 1:添加外部启动触发器
trg = addtrigger(d, "Digital", "StartTrigger", "External", "Dev1/PFI0");
trg.Condition = "RisingEdge";
d.DigitalTriggerTimeout = 30;

第 4 个参数是 Source(外部信号使用 "External")。第 5 个参数是 Destination(设备端子)。两者顺序颠倒是此领域最常见的错误。触发条件("RisingEdge"、"FallingEdge")在 addtrigger 返回的触发器对象(trg.Condition)上设置,而不是在 DataAcquisition 对象上设置。不存在 d.DigitalTriggerCondition 属性——虚构此属性可以通过静态检查,但会在运行时出错。

模式 2:ScansAvailableFcn 函数体——通过 read 提取数据,绝不使用 evt.Data
d.ScansAvailableFcnCount = round(d.Rate * 0.5);
d.ScansAvailableFcn = @(src, ~) onBlock(src);
d.ErrorOccurredFcn  = @(~, evt) fprintf("DAQ error: %s\n", evt.Error.message);

function onBlock(src)
    [data, t] = read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix");
    plot(t, data); drawnow limitrate;
end

evt 参数仅包含 NumElementsAvailable;它没有 Data 或 TimeStamps。强烈建议连接 ErrorOccurredFcn——否则,回调异常会被悄悄吞掉,运行也会“成功”,但每次触发都会抛出异常。对于严格移植没有 ErrorOccurred 监听器的旧脚本,应先询问用户,再添加监听器,不要擅自插入。

模式 3:阻塞等待采集完成——不存在 wait(d)
start(d, "Duration", seconds(10));
while d.Running
    pause(0.05);
end

daq.interfaces.DataAcquisition 上不存在 wait(d)。可以轮询 d.Running,或依赖 start(d, "Duration", ...),并在回调中设置停止条件。

模式 4:带自动补充缓冲区的连续 AO 播放
d = daq("ni");
d.Rate = 1000;
addoutput(d, "Dev1", "ao0", "Voltage");
d.ScansRequiredFcnCount = d.Rate;
d.ScansRequiredFcn = @(src, ~) write(src, generateNextBlock());
preload(d, generateNextBlock());
preload(d, generateNextBlock());
start(d, "Continuous");

preload 仅适用于输出——在仅输入的配置中调用会报错。在启动前预加载两个数据块,可为首次触发 ScansRequiredFcn 留出缓冲空间。

模式 5:通过嵌套函数或句柄类共享回调间状态
function runStreamingAcquisition()
    d = daq("ni");
    addinput(d, "Dev1", "ai0", "Voltage");
    d.Rate = 1000;
    d.ScansAvailableFcnCount = 200;

    scansRead = 0;
    target    = d.Rate * 5;
    d.ScansAvailableFcn = @(src, ~) onBlock(src);
    d.ErrorOccurredFcn  = @(~, evt) fprintf("DAQ error: %s\n", evt.Error.message);

    start(d, "Continuous");
    while d.Running
        pause(0.05);
    end

    function onBlock(src)
        data = read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix");
        scansRead = scansRead + size(data, 1);
        if scansRead >= target
            stop(src);
        end
    end
end

嵌套函数通过引用捕获 scansRead,因此更新会在多次触发间保留。不要使用 src.UserData.X = src.UserData.X + ...——这种模式无法保留状态;每次触发时计数器都会重置,闭环控制会悄无声息地始终输出零。完整的替代方案(句柄类、完整重写 UserData)及其权衡见 references/callback-state-patterns.md。

约定

  • 强烈建议在设置任何其他 *Fcn 回调时,同时连接 d.ErrorOccurredFcn,否则监听器会吞掉回调异常。对于严格移植缺少 ErrorOccurred 监听器的旧脚本,应向用户说明这种权衡,而不是悄悄添加处理程序——添加它是合理的默认做法,但忠于源代码同样有其合理性。
  • 始终在 ScansAvailableFcn 中通过 read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix") 读取数据。切勿使用 evt.Data 或 evt.TimeStamps。
  • 始终在 addtrigger 后验证返回的触发器对象——确认 Source 和 Destination 符合预期。
  • 切勿使用 wait(d)。应轮询 d.Running,或使用 start(d, "Duration", ...)。
  • 切勿在回调中修改 d.UserData 的字段(src.UserData.X = src.UserData.X + ...)。状态必须存储在由闭包捕获的变量、句柄类包装器中,或通过整体重写 UserData 结构体来更新。
  • 切勿对仅输入型 DataAcquisition 调用 preload。它仅适用于输出。
  • 优先使用 start(d, "Duration", seconds(N)),而非 start(d, "NumScans", N) 来执行有限时长采集。NumScans 会被静默强制转换或忽略。
  • 优先使用现代函数名称:daqlist 而非 daq.getDevices,daqreset 而非 daq.reset,daq("ni") 而非 daq.createSession('ni')。

常见错误

错误错误原因正确做法
addtrigger(d, "Digital", "StartTrigger", "Dev1/PFI0", "External")源和目标顺序颠倒。第 4 个参数是源,第 5 个参数是目标。addtrigger(d, "Digital", "StartTrigger", "External", "Dev1/PFI0")
在 ScansAvailableFcn 中调用 plot(evt.TimeStamps, evt.Data)evt 是 ElementsAvailableInfo;其中只有 NumElementsAvailable。此调用会静默失败。[data, t] = read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix")
wait(d)daq.interfaces.DataAcquisition 上没有此方法。调用会报错。while d.Running, pause(0.05); end
src.UserData.Counter = src.UserData.Counter + n通过 src.UserData 修改字段不会在回调触发之间持久保留。在嵌套函数中使用闭包变量,或使用句柄类包装器。请参阅 callback-state-patterns.md。
对仅包含输入通道的 DAQ 调用 preload(d, ...)preload 仅适用于输出。对于输入,直接调用 start(d, ...)。无需准备或预加载。
start(d, "NumScans", 1000)NumScans 会被忽略——并发出警告。缓冲区大小由 preload 或 read 决定。start(d, "Duration", seconds(N)),或使用 preload 的大小。
s.IsContinuous = true; s.startBackground();两者都属于 session API。现代 API 没有 IsContinuous 属性。start(d, "Continuous")
addlistener(d, 'DataAvailable', @cb)监听器事件已重命名为对象上的 *Fcn 属性。d.ScansAvailableFcn = @cb
s.queueOutputData(block)属于 session API。现代 API 使用 preload(初始数据)和 write(补充数据)。在 start 前调用 preload(d, block);在 ScansRequiredFcn 中调用 write(d, block)。

参考资料

  • references/session-to-modern-mapping.md — 列出所有常见误用的旧版函数和属性及其完整重命名对照表。只要旧脚本中出现 session API 标识,就应加载此文件。
  • references/canonical-snippets.md — 提供上述五种模式的精简、独立且可运行示例。编写包含多项功能的脚本并需要经过验证的参考示例时,请加载此文件。
  • references/callback-state-patterns.md — 介绍四种状态共享方式(UserData / 闭包 / 句柄类 / 嵌套函数)、各自适用场景,以及错误选择导致的静默失败模式。任何回调需要跨触发共享状态时,请加载此文件。
  • scripts/verifyDataAcquisition.m — 在实际执行前,对 DataAcquisition 对象及其源脚本进行静态检查。返回结构化报告,标出出现频率最高的四类静默问题。

版权所有 2026 The MathWorks, Inc.


评论

支持 Markdown