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. 01session API呼び出しをDataAcquisitionに対応付け
  2. 02トリガーとクロックの設定ガイド
  3. 03コールバック駆動のストリーミング
  4. 04出力バッファーと自動補充の説明
  5. 05見落とされやすいスクリプトエラーの検査

活用シーン

  1. 01daq.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

詳細

レガシーコードを最新の DataAcquisition インターフェイスに移植する

セッションベースの従来の Data Acquisition Toolbox コード(daq.createSession、addAnalogInputChannel、DataAvailable リスナー、startBackground、queueOutputData、wait)を、R2020a で導入された最新の DataAcquisition インターフェイス(daq("ni")、addinput、ScansAvailableFcn、start、write、preload)に移行します。また、認知負荷が高いと間違いやすい最新 API のパターンを組み合わせた、新しい複数機能対応 DAQ スクリプトの作成も扱います。

使用する場面

  • daq.createSession、addAnalogInputChannel、addAnalogOutputChannel、addCounterInputChannel、addCounterOutputChannel、addDigitalChannel を呼び出す既存のスクリプトを移植する場合。
  • DataAvailable/DataRequired/ErrorOccurred リスナーを ScansAvailableFcn/ScansRequiredFcn/ErrorOccurredFcn に置き換える場合。
  • startBackground/startForeground/s.wait() によるライフサイクル呼び出しを置き換える場合。
  • queueOutputData を preload と write に置き換える場合。
  • 外部トリガー、連続取得、コールバック駆動のストリーミング、補充を伴うアナログ出力、コールバック間で共有する状態のうち、2 つ以上を組み合わせた新しい DAQ スクリプトを作成する場合。
  • Undefined function 'wait' for input arguments of type 'daq.interfaces.DataAcquisition' や Unrecognized method, property, or field 'Data' for class 'matlabshared.asyncio.buffer.ElementsAvailableInfo' のようなエラーをデバッグする場合。

使用しない場面

  • トリガーもコールバックも使わない、単一チャネルのフォアグラウンド取得(例:「ai0 から 10 kHz で 1 秒間の電圧を取得してプロットする」)。この規模なら最新 API はシンプルで、このスキルは余分な手間になります。
  • DAQ ベンダーの選定や、NI 以外のハードウェアの評価。このスキルのエビデンスは NI に基づいています。
  • 取得済みデータの信号処理や解析(フィルタリング、スペクトル解析など)。このスキルでは DataAcquisition インターフェイスによるデータの取得と生成のみを扱い、後処理は扱いません。
  • Simulink、App Designer、またはリアルタイムターゲット向けの DAQ ワークフロー。
  • matlab.unittest テストスイートやフレームワーク形式のテストクラス(パラメーター化されたフィクスチャ、assumeTrue によるゲーティング、引数数の契約テスト、ヘルパークラスの階層など)の最新化。API の置き換えはこのスキルの対象ですが、テストハーネスの構成(親クラスの削除、フィクスチャの再設計、削除された契約を対象とするテストの廃止)は対象外です。このスキルを使ってテスト本体内の 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。ライブオブジェクトを調べ、ソースファイルを検索することで、頻度の高い4つのサイレントな不備(ErrorOccurredFcn の欠落、コールバックソース内の evt.Data、wait(d) トークン、UserData.X = UserData.X + ... によるフィールド変更)を検出します。利用可能な場合は mcp__matlab__run_matlab_file で実行するか、ユーザーのプロジェクトにコピーしてください。

  9. ライブ検証。 ユーザーが指定した全時間ではなく、短い時間(例:1~2秒)で実行します。スクリプトが問題なく start に到達すること、コールバックが少なくとも1回呼び出されること、ErrorOccurredFcn からエラーが出力されないことを確認してください。保存済みの .m ファイルに対して mcp__matlab__run_matlab_file を使用してください。 mcp__matlab__evaluate_matlab_code は使用しないでください。eval文字列バッファーはスクリプトモードで実行されるため、Pattern 5 や多くのコールバック本体で必要となるローカル関数やネスト関数の定義が拒否されます。

主な機能

機能用途ツールボックス利用可能なバージョン
daqDataAcquisition オブジェクトを作成します(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
preloadstart(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
daqresetDAQ サブシステムをリセットします(daq.reset に代わるものです)Data Acquisition ToolboxR2020a

DataAcquisition のプロパティ:Rate、Running、NumScansAcquired、NumScansOutputByHardware、ScansAvailableFcn、ScansAvailableFcnCount、ScansRequiredFcn、ScansRequiredFcnCount、ErrorOccurredFcn、DigitalTriggerTimeout、UserData。

パターン

以下の5つの代表的なパターンは、検証済みコードとともに references/canonical-snippets.md にすべて掲載されています。以下にはそれぞれ、エージェントが負荷の高い状況でも記憶をたどれるよう、最小限の要点を示すスニペットを記載しています。完全な実行可能形式については、リファレンスを読み込んでください。

パターン 1:外部開始トリガーを追加する
trg = addtrigger(d, "Digital", "StartTrigger", "External", "Dev1/PFI0");
trg.Condition = "RisingEdge";
d.DigitalTriggerTimeout = 30;

第4引数は Source(外部信号の場合は "External")です。第5引数は Destination(デバイスの端子)です。これらを逆にするのは、この分野で最もよくあるエラーです。トリガー条件("RisingEdge"、"FallingEdge")は、DataAcquisition オブジェクトではなく、addtrigger が返すトリガーオブジェクト(trg.Condition)に設定します。d.DigitalTriggerCondition プロパティは存在しません。これをでっち上げても静的 lint は通りますが、実行時にエラーになります。

パターン 2:ScansAvailableFcn の本体 — evt.Data ではなく read でデータを取り出す
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

wait(d) は daq.interfaces.DataAcquisition に存在しません。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 は出力専用です。入力のみの構成で呼び出すとエラーになります。start の前に2つのブロックをプリロードしておくと、最初の 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, "NumScans", N)よりもstart(d, "Duration", seconds(N))を優先してください。NumScansは警告なしに強制変換されるか、無視されます。
  • 最新の関数名を優先してください。daq.getDevicesよりdaqlist、daq.resetよりdaqreset、daq.createSession('ni')よりdaq("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 + nsrc.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();どちらもセッション API です。最新の API に IsContinuous プロパティはありません。start(d, "Continuous")
addlistener(d, 'DataAvailable', @cb)リスナーイベントの名前は、オブジェクトの *Fcn プロパティに変更されました。d.ScansAvailableFcn = @cb
s.queueOutputData(block)セッション API です。最新の API では、初期データに preload、補充に write を使用します。start の前に preload(d, block) を呼び出し、ScansRequiredFcn から write(d, block) を呼び出します。

参考資料

  • references/session-to-modern-mapping.md — 間違ってそのまま移植されがちなすべての関数とプロパティを網羅した、完全な名前変更表です。レガシースクリプトにセッション API のトークンが含まれている場合に読み込んでください。
  • references/canonical-snippets.md — 上記の5つのパターンを、最小限かつ自己完結型で実行可能な形式にしたものです。複数の機能を組み合わせたスクリプトを作成する際に、検証済みの基準となる例が必要な場合に読み込んでください。
  • references/callback-state-patterns.md — 4つの状態共有方法(UserData/クロージャ/ハンドルクラス/ネスト関数)、それぞれの使い分け、および誤った方法を選んだ場合に通知されずに発生する失敗について説明しています。コールバック間で状態を共有する必要がある場合に読み込んでください。
  • scripts/verifyDataAcquisition.m — 実行前に DataAcquisition オブジェクトとそのソーススクリプトを静的チェックします。発生頻度が最も高い4つの見落としを示す、構造化されたレポートを返します。

Copyright 2026 The MathWorks, Inc.


コメント