To workspaceブロックの変数名を取得してcsvで保存する

## はじめに
Simulinkの結果をcsvに保存するときにTo workspaceブロックを使っていますが、
そのときモデル上で配置した順に並べて保存したいというときのメモ。
ブロックから変数名を取得して、その配置順に変数名をラベルとして保存します。

## 環境
MATLAB2023b Simulink

## 手順
### モデルファイルを準備する

To Workspaceブロックに入力と出力を保存しますが以下の設定で行います。
・モデル設定→単一のシミュレーション出力のチェックを外す
・To Workspaceブロックの保存形式を配列にする

今回は図のように左から右の順に1列ごとずつ保存します。　列はそろえておきます。
左側のモデルはてきとうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556627/48f85db6-ad8f-9687-bb13-b0a47d06796c.png)
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556627/d8a041db-e609-e375-7a9c-bb0c89545cea.png  width="20%">
↓出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556627/8bf1ada5-4fa0-c28e-23b4-2a65596d8281.png)

### ブロックのパス・変数名を取得する
```MATLAB
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`となります。
```MATLAB
blocktypes = get_param(blockpaths, 'BlockType')    % 確認用 ブロックの種類を取得
```
```
blocktypes =
                ︙
    {'ToWorkspace'}
    {'ToWorkspace'}
 ```
ということで、再び`find_system`を実行します。`tw_paths`には`BlockType`が`ToWorkspace`のブロック名のみが入ります。
```MATLAB
tw_paths = find_system(mdl, 'BlockType', 'ToWorkspace'); % To Workspaceのブロックのパスを取得
```
`'DialogParameters'`で設定できるパラメータを確認します。
```MATLAB
tw_params = get_param(tw_paths,'DialogParameters'); % 確認用 使用できるパラメータを取得
```
```
tw_params{1} = 
     VariableName: [1×1 struct]
    MaxDataPoints: [1×1 struct]
                    ︙
```
このうち`VariableName`が変数名に対応するため、これを取得します。セル配列となります。
```MATLAB
tw_names = get_param(tw_paths, 'VariableName');     % To Workspaceブロックの変数名を取得
```
```
tw_names =
    {'x1'}
    {'t1'}
    {'x2'}
    {'y1'}
    {'y2'}
```
### ブロックの位置を取得する
ブロックの位置を取得するときは`'Position'`プロパティを使います。
```MATLAB
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`でセル配列を行列に変換しています。
このとき、並び替えたインデックスを出力しておき、変数名のセル配列のインデックスとすることで同じ順番に並び替えることができます。
```MATLAB
[~, 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に保存できます。
 ```MATLAB
 T = eval("table("+ strjoin(sorted_names,",") +")")      % 変数名からテーブルを作成
writetable(T, 'out.csv');                               % csvに出力
 ```
 csvファイルを開くと変数名で保存されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556627/8bf1ada5-4fa0-c28e-23b4-2a65596d8281.png)

ラベル名を追加・変更したければ、Table型のままでいろいろできます。

### 全文
```MATLAB
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を中心に扱う場合は使えるかもしれません。


## 参考
https://jp.mathworks.com/help/simulink/slref/get_param.html