はじめに
Simulinkの結果をcsvに保存するときにTo workspaceブロックを使っていますが、
そのときモデル上で配置した順に並べて保存したいというときのメモ。
ブロックから変数名を取得して、その配置順に変数名をラベルとして保存します。
環境
MATLAB2023b Simulink
手順
モデルファイルを準備する
To Workspaceブロックに入力と出力を保存しますが以下の設定で行います。
・モデル設定→単一のシミュレーション出力のチェックを外す
・To Workspaceブロックの保存形式を配列にする
今回は図のように左から右の順に1列ごとずつ保存します。 列はそろえておきます。
左側のモデルはてきとうです。
↓出力結果
ブロックのパス・変数名を取得する
mdl = 'GetVarName'; % モデル名
blockpaths = find_system(mdl, 'Type', 'Block') % 確認用 すべてのブロックのパスを取得
ここでblockpaths
の中身は以下のようにブロック名までのパスとなっています。
blockpaths =
{'GetVarName/Clock' }
{'GetVarName/Demux' }
{'GetVarName/Demux1' }
︙
{'GetVarName/To Workspace' }
{'GetVarName/To Workspace1'}
︙
ブロック名は変える可能性があるのでブロックの種類で判別します。
To Workspace
のBlockType
はToWorkspace
となります。
blocktypes = get_param(blockpaths, 'BlockType') % 確認用 ブロックの種類を取得
blocktypes =
︙
{'ToWorkspace'}
{'ToWorkspace'}
ということで、再びfind_system
を実行します。tw_paths
にはBlockType
がToWorkspace
のブロック名のみが入ります。
tw_paths = find_system(mdl, 'BlockType', 'ToWorkspace'); % To Workspaceのブロックのパスを取得
'DialogParameters'
で設定できるパラメータを確認します。
tw_params = get_param(tw_paths,'DialogParameters'); % 確認用 使用できるパラメータを取得
tw_params{1} =
VariableName: [1×1 struct]
MaxDataPoints: [1×1 struct]
︙
このうちVariableName
が変数名に対応するため、これを取得します。セル配列となります。
tw_names = get_param(tw_paths, 'VariableName'); % To Workspaceブロックの変数名を取得
tw_names =
{'x1'}
{'t1'}
{'x2'}
{'y1'}
{'y2'}
ブロックの位置を取得する
ブロックの位置を取得するときは'Position'
プロパティを使います。
tw_positions = get_param(tw_paths, 'Position'); % To Workspaceブロックの位置を取得
tw_positions =
{[ 955 47 1000 73]}
{[ 850 -25 905 5]}
{[ 955 107 1000 133]}
{[ 1160 47 1205 73]}
{[1160 107 1205 133]}
このようにセル配列で返ってきます。1つめがX座標、2つめがY座標の値になります。(左上と右下の座標?)
最初の図の順に保存したいので1列目を基準に並び替えます。
並び替えるときはsortrows
を使うと便利です。1列目に同じ値があるとき2列目を基準に並び替えるため自然と列ごとになります。cell2mat
でセル配列を行列に変換しています。
このとき、並び替えたインデックスを出力しておき、変数名のセル配列のインデックスとすることで同じ順番に並び替えることができます。
[~, sorted_idx] = sortrows(cell2mat(tw_positions), 1); % 位置で並び変える
sorted_names = tw_names(sorted_idx); % 同じインデックス
sorted_names =
{'t1'}
{'x1'}
{'x2'}
{'y1'}
{'y2'}
csvに保存する
Table型を使うと変数名をそのままラベルとして扱えるため、取得したTo Workspaceの変数名をeval
に渡し実行します。そのままcsvに保存できます。
T = eval("table("+ strjoin(sorted_names,",") +")") % 変数名からテーブルを作成
writetable(T, 'out.csv'); % csvに出力
ラベル名を追加・変更したければ、Table型のままでいろいろできます。
全文
mdl = 'GetVarName'; % モデル名
%blockpaths = find_system(mdl, 'Type', 'Block') % 確認用 すべてのブロックのパスを取得
%blocktypes = get_param(blockpaths, 'BlockType') % 確認用 ブロックの種類を取得
tw_paths = find_system(mdl, 'BlockType', 'ToWorkspace'); % To Workspaceのブロックのパスを取得
%tw_params = get_param(tw_paths,'DialogParameters'); % 確認用 使用できるパラメータを取得
tw_names = get_param(tw_paths, 'VariableName'); % To Workspaceブロックの変数名を取得
tw_positions = get_param(tw_paths, 'Position'); % To Workspaceブロックの位置を取得
[~, sorted_idx] = sortrows(cell2mat(tw_positions), 1); % 位置で並び変える
sorted_names = tw_names(sorted_idx); % 同じインデックス
T = eval("table("+ strjoin(sorted_names,",") +")") % 変数名からテーブルを作成
writetable(T, 'out.csv'); % csvに出力
おわりに
ブロック1つ1つのパラメータも細かく取得できるんだなという感想。
順番を気にすることはないかもしれませんが、csvを中心に扱う場合は使えるかもしれません。
参考