メインコンテンツ

このページは機械翻訳を使用して翻訳されました。最新版の英語を参照するには、ここをクリックします。

MDF ファイルのチャネルを Simulink モデル入力ポートにマッピングする

この例では、MDF ファイルからチャネルをプログラムでマップし、Simulink ® モデルの入力ポートを介してそのデータを使用する方法を示します。これは、Simulink モデルの入力ポート名の収集を実行し、それらを特定の MDF ファイルの内容と関連付けます。次に、モデルの実行時に MDF ファイルから取得されたチャネル データを消費するリンクがそれらの間に作成されます。

モデルの詳細を取得

サンプルモデル名を定義して開きます。

mdlName = "ModelForMDFInput";
open_system(mdlName);

モデルとその入力に関する全体的な情報を取得するには、createInputDataset (Simulink) 関数を使用します。データセット信号要素を timetable として構成するには、DatasetSignalFormat オプションを "timetable" として指定します。

dsObj = createInputDataset(mdlName, UpdateDiagram=true, DatasetSignalFormat="timetable")
dsObj = 
Simulink.SimulationData.Dataset '' with 2 elements

                            Name      BlockPath 
                            ________  _________ 
    1  [2x1 timetable]      triangle  ''       
    2  [1x1 struct   ]      busInput  ''       

  - Use braces { } to access, modify, or add elements using index.

モデル入力ポート名を取得する

このモデルにはバスと個別の入力ポートの両方があります。helperGetMdlInputNames 関数は、モデル内での定義方法に関係なく、すべてのモデル入力の名前を取得する方法を示します。

mdlInputNames = helperGetMdlInputNames(mdlName)
mdlInputNames = 4×1 string
    "triangle"
    "pwm"
    "pwm_level"
    "pwm_filtered"

MDFファイルを調査する

モデルの入力ポート名がわかったので、MDF ファイルに存在するチャネルを確認して、それらの一致を試みることができます。mdfChannelInfo 関数を使用すると、MDF ファイル内にある利用可能なチャネルにすばやくアクセスできます。

mdfName = "CANape.MF4";
channelInfo = mdfChannelInfo(mdfName)
channelInfo=42×13 table
                     Name                     GroupNumber    GroupNumSamples    GroupAcquisitionName    GroupComment    GroupSourceName    GroupSourcePath    DisplayName       Unit                             Comment                         ExtendedNamePrefix    SourceName     SourcePath
    ______________________________________    ___________    _______________    ____________________    ____________    _______________    _______________    ___________    ___________    _________________________________________________    __________________    ___________    __________

    "Counter_B4"                                   1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Single bit demo signal (bit from a byte shifting)          XCPsim          <undefined>      XCPsim  
    "Counter_B5"                                   1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Single bit demo signal (bit from a byte shifting)          XCPsim          <undefined>      XCPsim  
    "Counter_B6"                                   1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Single bit demo signal (bit from a byte shifting)          XCPsim          <undefined>      XCPsim  
    "Counter_B7"                                   1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Single bit demo signal (bit from a byte shifting)          XCPsim          <undefined>      XCPsim  
    "PWM"                                          1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Pulse width signal from PWM_level and Triangle             XCPsim          <undefined>      XCPsim  
    "PWMFiltered"                                  1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Low pass filtered PWM signal                               XCPsim          <undefined>      XCPsim  
    "PWM_Level"                                    1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    <undefined>                                                XCPsim          <undefined>      XCPsim  
    "Triangle"                                     1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    Triangle test signal used for PWM output PWM               XCPsim          <undefined>      XCPsim  
    "ampl"                                         2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    Amplitude of channel 1-3                                   XCPsim          <undefined>      XCPsim  
    "channel1"                                     2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    FLOAT demo signal (sine wave)                              XCPsim          <undefined>      XCPsim  
    "map1_8_8_uc_measure"                          1              1993                 10 ms               10 ms          <undefined>          XCPsim             ""         <undefined>    8*8 fixed axis,  permanently morphing                      XCPsim          <undefined>      XCPsim  
    "syncArrayStruct.mem_charArray[000]"           2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    <undefined>                                                XCPsim          <undefined>      XCPsim  
    "syncArrayStruct.mem_charArray[001]"           2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    <undefined>                                                XCPsim          <undefined>      XCPsim  
    "syncArrayStruct.mem_doubleArray[000]"         2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    <undefined>                                                XCPsim          <undefined>      XCPsim  
    "syncArrayStruct.mem_doubleArray[001]"         2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    <undefined>                                                XCPsim          <undefined>      XCPsim  
    "syncArrayStruct.mem_floatArray[000]"          2               199                 100ms               100ms          <undefined>          XCPsim             ""         <undefined>    <undefined>                                                XCPsim          <undefined>      XCPsim  
      ⋮

関心のある項目を管理するためのテーブルを構築する

テーブルを使用して、モデルの入力ポートを MDF チャネルにマッピングします。

channelTable = table();
channelTable.PortNames = mdlInputNames;
n = size(channelTable.PortNames,1);
channelTable.GroupNumber = NaN(n,1);
channelTable.ChannelName = strings(n,1);
channelTable
channelTable=4×3 table
      PortNames       GroupNumber    ChannelName
    ______________    ___________    ___________

    "triangle"            NaN            ""     
    "pwm"                 NaN            ""     
    "pwm_level"           NaN            ""     
    "pwm_filtered"        NaN            ""     

入力ポートとチャネルのマッチングを実行する

helperReportChannelInfo 関数は、MDF ファイル内でモデルの入力ポート名と一致するチャネル名を検索します。見つかった場合、チャネルの詳細がテーブルに記録されます。具体的には、ファイル内で指定されたチャネルが存在するチャネル グループ番号と、その実際の定義名です。実際のチャネル名はモデル ポート名と完全に一致しないことに注意してください。この例では、チャネル名の一致は大文字と小文字を区別せずに実行され、アンダースコア文字は無視されます。このアルゴリズムは、アプリケーション固有の一致基準に基づいて必要に応じて調整できます。

channelTable = helperReportChannelInfo(channelTable, channelInfo)
channelTable=4×3 table
      PortNames       GroupNumber     ChannelName 
    ______________    ___________    _____________

    "triangle"             1         "Triangle"   
    "pwm"                  1         "PWM"        
    "pwm_level"            1         "PWM_Level"  
    "pwm_filtered"         1         "PWMFiltered"

Simulinkデータセットオブジェクトにチャネルデータを入力する

先ほど作成したデータセット オブジェクトには、単一の timetable と timetable の構造体の両方が含まれています。これにより、データを再度割り当てることが多少困難になります。留意すべき点は次のとおりです。

  • dataset オブジェクトには異なる要素 (timetable と timetable の構造体) があるため、コレクションを手動で管理し、正しい場所に書き込んでいることを確認する必要があります。

  • mdfRead 関数は、デフォルトでデータを物理値として読み取ります。ただし、関心のあるチャネルの 1 つである「PMW」には、ValueToText 変換が含まれています。生の数値が読み取られてデータセット オブジェクトに入力されるようにするには、ReadRaw オプションを true に設定する必要があります。

for ii = 1:dsObj.numElements
    switch class(dsObj.getElement(ii))
        case 'timetable'
            % Read the input port data from the MDF file one channel at a time.
            mdfData = mdfRead(mdfName, Channel=channelTable.ChannelName(ii), ReadRaw=true);
            % Populate the dataset object.
            dsObj{ii} = mdfData{1};
        
        % For a port that accepts a bus, the data to be loaded must be arranged in a struct
        % that matches the structure of the bus object attached to the input port.
        case 'struct'
            names = fieldnames(dsObj.getElement(ii));
            for jj = 1:numel(names)
                % Find row index of this signal name in the channel table.
                rowIdx = find(channelTable.PortNames == names(jj));
                % Read the input port data from the MDF file one channel at a time.
                mdfData = mdfRead(mdfName, Channel=channelTable.ChannelName(rowIdx), ReadRaw=true);
                % Populate the dataset object.
                dsObj{ii}.(channelTable.PortNames{rowIdx}) = mdfData{1};                
            end
    end
end
dsObj
dsObj = 
Simulink.SimulationData.Dataset '' with 2 elements

                               Name      BlockPath 
                               ________  _________ 
    1  [1993x1 timetable]      triangle  ''       
    2  [1x1 struct      ]      busInput  ''       

  - Use braces { } to access, modify, or add elements using index.

データセットをSimulinkモデルへの入力として有効にする

set_param(mdlName, "LoadExternalInput", "on");
set_param(mdlName, "ExternalInput", "dsObj");

モデルの実行

モデルを実行すると、MDF ファイルのチャネル データが指定された入力ポートに適切にマップされ、期待どおりに Simulink を通じてプロットされることに注意してください。

open_system(mdlName);
bp = find_system(mdlName, "BlockType", "Scope");
open_system(bp);
pause(1)
sim(mdlName, "TimeOut", 10);

補助関数

function mdlInputNames = helperGetMdlInputNames(mdlName)
% helperGetMdlInputNames Find input port names of a Simulink model.
%
% This function takes in the name of a Simulink model and returns the names of each model input. This specific model has 
% both a bus and a standalone input port going into it. To drive an input port that expects a bus means you need to supply 
% the signals as timetables in a struct that matches the structure of the bus object attached to the input port.

% Test to see if the model is currently loaded in memory.
isLoaded = bdIsLoaded(matlab.lang.makeValidName(mdlName));

% If the model is not open then load it.
if ~isLoaded
    load_system(mdlName);
end

dsObj = createInputDataset(mdlName, UpdateDiagram=true);
numElements = dsObj.numElements;
isStruct = zeros(1, numElements);

% Check to see if any of the elements in the returned dataset object are
% structs. If they are, assume they are for an input port that accepts a bus.
for elementIdx = 1:numElements
    isStruct(elementIdx) = isa(dsObj.getElement(elementIdx),"struct");
end

% Initialize an empty string array to hold names of all input ports. If
% your model has a very large number of inputs, consider preallocating the
% string array for performance.
mdlInputNames = string.empty;
for idx = 1:numElements
    if isStruct(idx)
        % Get names of signals from a bus input port.
        mdlInputNames = [mdlInputNames; string(fieldnames(dsObj.getElement(idx)))]; %#ok<AGROW> 
    else
        % Get signal name from a non-bus input port.
        mdlInputNames = [mdlInputNames; string(dsObj.getElement(idx).Name)]; %#ok<AGROW> 
    end
end

end
function channelTableOut = helperReportChannelInfo(channelTableIn, channelInfo)
% channelTableOut Reports if a channel is present in a set of channel names.

% Assign the output data.
channelTableOut = channelTableIn;

% Remove underscores and make everything lowercase for matching.
inPortChannelNames = lower(erase(channelTableIn.PortNames,"_"));
mdfChannelNames = lower(erase(channelInfo.Name,"_"));

% Match the input channel names to the channel names in the MDF file.
[~, inPortIdx] = ismember(inPortChannelNames, mdfChannelNames);

% Assign the relevant information back to the channel table.
channelTableOut.GroupNumber = channelInfo.GroupNumber(inPortIdx);
channelTableOut.ChannelName = channelInfo.Name(inPortIdx);

end