SimulinkモデルのGotoブロックとFromブロックを自動で結線する

#SimulinkモデルのGotoブロックとFromブロックを自動で結線する
業務で、以前から社内で使われてきたsimulinkモデルのリーバスを命じられたが、Gotoブロック、Fromブロックが多用されすぎてサブシステム同士の接続すら追うことが困難だった。
そこで、GotoブロックとFromブロックを自動で接続するスクリプトを作成してみた。


#対象のSimulinkモデル
検証用として以下のSimulinkモデルを使用する。
二階層のモデルで、Subsystem/内でGotoブロック、Fromブロックが複数存在している。目標は、検証用Simulinkモデルに対して、対応するGotoブロックとFromブロックを結線するスクリプトを作成すること。

![target_model.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693510/58bffa1f-f8dd-860f-b6e0-dfd3bcfbe697.png)

#コード
```MATLAB:connet_Goto_and_From.m
clear;
clc;

%% 対象のシステムを設定
model_name = "sample.slx";
target_system = "sample/Subsystem/";

%% モデル読み込み
open_system(model_name);

%% GotoブロックとFromブロックを自動結線
from_block_list = find_system(target_system, 'SearchDepth', '1', 'BlockType', 'From'); %Fromブロック一覧を取得   
goto_block_list = find_system(target_system, 'SearchDepth', '1', 'BlockType', 'Goto'); %Gotoブロック一覧を取得

for i = 1:length(from_block_list)
    ph_from_block = get_param(from_block_list{i}, 'PortHandles');
    line = get_param(ph_from_block.Outport, 'Line');                          %Fromブロックの出力信号線(line)を取得
    if line == -1
        continue;
    end
    dst = get_param(line, 'DstPortHandle');                                   %lineの接続先を取得
    
    Tag_from_block = get_param(from_block_list{i}, 'GotoTag');
    for j = 1:length(goto_block_list)
        Tag_goto_block = get_param(goto_block_list{j}, 'GotoTag');
        
        if strcmp(Tag_from_block, Tag_goto_block)                             %FromブロックとGotoブロックのGotoタグを比較
            delete_line(line);                                                %Fromブロックに対応するGotoブロックが存在する時、Fromブロックの出力信号線を削除
            ph_go_to_block = get_param(goto_block_list{j}, 'PortHandles');
            line = get_param(ph_go_to_block.Inport, 'Line');                  %Gotoブロックの入力信号線(line)を取得
            src = get_param(line, 'SrcPortHandle');                           %lineの出力元を取得
            for k = 1:length(dst)
                add_line(target_system, src, dst(k), 'autorouting', 'smart'); %結線 
            end
            break;
        end
    end
end

%% GotoブロックとFromブロックを削除(※対応するFromブロックがないGotoブロックは残す)
deleted_goto_block = zeros(1, length(goto_block_list));                   %削除済みのGotoブロックのリスト. goto_block_listのインデックスを格納
for i = 1:length(from_block_list)
    
    Tag_from_block = get_param(from_block_list{i}, 'GotoTag');
    for j = 1:length(goto_block_list) 
        if deleted_goto_block(j) == 1                                     %goto_block_listでj番目のGotoブロックが削除されているときは以降の処理をスキップ
            continue;
        end
        Tag_goto_block = get_param(goto_block_list{j}, 'GotoTag');
        
        if strcmp(Tag_from_block, Tag_goto_block)                          %FromブロックとGotoブロックのGotoタグを比較
            ph_go_to_block = get_param(goto_block_list{j}, 'PortHandles');
            line = get_param(ph_go_to_block.Inport, 'Line');               %Gotoブロックの入力信号線(line)を取得
            delete_line(line);
            delete_block(goto_block_list{j});
            deleted_goto_block(j) = 1;                                     %削除済みのGotoブロックをdeleted_goto_blockに追加
            break;
        end
    end
    
    delete_block(from_block_list{i});
end
```

上記のコードを、検証用モデルに対して実行すると次のようになり、GotoブロックとFromブロックが接続されていることが確認できる。

![target_model_coneccted.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693510/ac6b7684-6fea-bbd8-1f8e-cd708d9ec40a.png)

大まかな処理の流れは以下。
GotoブロックとFromブロックが一対多であること、対応するFromブロックが存在しないGotoブロックは削除せずに残そうと思ったため、GotoブロックとFromブロックの結線を一通り行ってから、不要になったGotoブロックとFromブロックを削除するようにした。

```
1. Gotoブロック一覧とFromブロック一覧を取得
2. Fromブロックを一つ固定
3. Fromブロックに対応するGotoブロックを検索
4. Fromブロックの出力信号線を削除
5. Gotoブロックの入力元からFromブロックの接続先へ結線
6. 2から5を繰り返す
7. Gotoブロックと、Gotoブロックへの入力信号線と、Fromブロックを削除
```

また、検証用モデルとスクリプトは以下にあげた。誰かの役に立てば、うれしいなぁ。
まあ、処理の流れがわからなくなるほどGotoブロックを多用するモデルなんてそうそうあるわけないか・・・。

https://github.com/myzk-a/Matlab/tree/main/connet_Gotoblock_and_Fromblock

#参考にした情報
Simulink APIでのモデルの操作方法がわかりやすく書いてくれている。
大変参考になりました。
[Simulink API で MATLAB から Simulink を操る](https://blogs.mathworks.com/japan-community/2020/02/19/control-simulink-from-matlab-with-simulink-api/?s_tid=srchtitle_Simulink%2520API_1&from=jp)
[Simulink API で MATLAB から Simulink を操る②　～モデルの編集～](https://blogs.mathworks.com/japan-community/2021/07/09/edit-model-from-matlab-with-simulink-ap/?s_tid=srchtitle_Simulink%2520API_2&from=jp)