ぷち影響解析ツールが欲しい
Simulinkモデルを階層化するために、複数のSimulinkブロックを1つのサブシステムにまとめる事があります。
さて、他人の書いたモデルを解析していると入力ポートが20も30もあるサブシステムに出くわすことがありますが、これがチョットだけ困り者です。というのも、サブシステムの「とある入力信号」が、サブシステム内のどこに繋がっているのかパッと見て分からないからです。
入力がいっぱいあるサブシステム
(当然)入力ポートがいっぱいある
Simulinkに付属の機能もある
さて、実は最近のSimulinkには、影響解析機能が搭載されています。
気になる信号線を右クリックして「伝播先の強調」をクリックすると、
こんな感じで接続先を表示してくれます。
これはこれでいいのですが、私のやりたい事とはちょっと違います。というのも、実はこの例では、サブシステムがこんな感じになっているからです。
奥へ奥へと追いかけていって、最終的に実ブロックに当たるまで解析をしてくれます。ここでいう「実ブロック」とは、信号線や、Inport、Outportのように信号のルーティングをするだけの仮想ブロックではなく、「AND」のように実際に何らかの処理をしてくれるブロック、という意味です。
ちなみに、「どういう経路でここまできたか?」も上図のように色をつけて表示してくれます。
私のやりたい事
私はここまでして欲しくありません。単純に、サブシステムへの入力を指定したら、そのサブシステムの中にある入力ポートをパカパカ点滅させてくれるだけでよいのです。奥へ奥へと追いかけていく必要はありません。
これには理由があります。たとえば下図では、シアン色の入力ポート(passenger_down1)から信号線が延びていて、サブシステム(validate_passenger1)に接続されています。
「入力ポート(passenger_down1)が、サブシステム(validate_passenger1)の「down」端子に繋がっている」事が分かっただけで、何がどうなっているか理解できるようなモデルになっているのが普通です。「このサブシステムって何するやつなのか」を知るのに、サブシステムの中へ中へと追っていかないといけないようではダメです。
基本的に、
・サブシステムに適切な名前や、コメントがつけられていること
・サブシステムの入出力ポートに、適切な名前がつけられていること
この2点さえ守られていれば、 そのサブシステムをみただけで「あー、そういう仕事をしてるんだなー」と分かるはずです。それなのに奥へ奥へと追いかけてしまうと、かえって何のことやら分かりにくくなってしまいます。(万が一、何のためにあるのか分からないサブシステムを見つけたら、私はすぐにそれを解体してしまいます。)
さて、残念ながらこういう事をしてくれる「ぷち影響解析ツール」は存在しないように思います。単純すぎて高い値段がつけられないでしょうから、きっと作っても儲からないんでしょうね。。。
仕方が無いですから、自分で作ることにします。そのうち。
このくらいのトレース機能は、そもそもsimulinkに入っていて欲しいですよね。
ハイライトそのものは機能的にあるから、簡単にできるかなぁと思ってみましたが、やってみると、(ちゃんと作ろうとすると)意外とめんどくさいですね。
自分が作ったモデルであれば、ある程度モデルのスタイルもわかっているし、使い方も限定的でいけそうですが、今回の場合は、人様がつくった、どういうスタイルか、結線がちゃんとなっているかとか、いろいろ考え出すと大変^^;
しかも、今回も右クリックでやろうとすると、結線が分岐している場合、選択した結線のsrcから分岐している結線も全部選択されてしまいますし…
まぁ、このくらいであれば、ちゃっちゃっと日曜大工がてら作られてそうですが、私も単純なやつを(あまりエラー系だのは考えずに)作ってみましたので、勝手にコメント欄に記載してみます。(このせいで、検索エンジンとかから検索ワードでひっかかってしょうがない場合は、がんがん消しちゃってくださいませ:-))
sl_customization.m
—
function sl_customization(cm)
cm.addCustomMenuFcn(‘Simulink:ContextMenu’, @registerLineTraceMenu);
end
%%
function schemaFcns = registerLineTraceMenu()
schemaFcns = { @lineTraceOn, @lineTraceOff };
end
%%
function schema = lineTraceOn(~)
schema = registerLineTraceMenu_s( 0 );
end
function schema = lineTraceOff(~)
schema = registerLineTraceMenu_s( 1 );
end
%% 各メニューの登録関数
function schema = registerLineTraceMenu_s( index )
schema = sl_action_schema;
switch index
case 0
schema.label = sprintf( ‘Lineをトレース’);
schema.userdata = ‘on’; %dummy
case 1
schema.label = sprintf( ‘トレースを消す’);
schema.userdata = ‘none’;
end
schema.callback = @linetrace;
end
function linetrace(callbackInfo)
% 選択された線の取得
tmp = find_system(callbackInfo.uiObject.Handle, …
‘findall’,’on’,’LookUnderMasks’,’off’, …
‘Type’, ‘Line’, ‘Selected’, ‘on’);
% 選択されていない場合は終了
if length(tmp) == 0
return;
end
for i = 1 : length(tmp)
port_handle = get_param(tmp(i), ‘DstPortHandle’);
lr_subsystem = get_param(get_param(tmp(i), ‘DstPortHandle’), ‘Parent’);
if length(port_handle) == 0
continue;
end
if ~iscell(lr_subsystem)
% 複数あるときにセルで格納されるみたいなので
% 1つしかないときもセルに変換しておく
lr_subsystem = cellstr(lr_subsystem);
end
for j = 1 : length(port_handle)
lr_sub_j = lr_subsystem(j);
% サブシステムに所属しているかどうかチェック
port_parent = get_param(port_handle(j), ‘Parent’);
if strcmp(get_param(port_parent, ‘Type’), ‘block’) == 0
continue;
end
if strcmp(get_param(port_parent, ‘BlockType’), ‘SubSystem’) == 0
continue;
end
% 表示画面以外での選択線があるので、チェックしてからハイライト
if get_param(get_param(char(lr_sub_j), ‘Parent’), ‘Handle’) == callbackInfo.uiObject.Handle
%ハイライトするポートの検索
x = find_system(lr_sub_j, ‘Port’, int2str(get_param(port_handle(j), ‘PortNumber’)), ‘BlockType’, ‘Inport’);
% ハイライト処理
if strcmp(callbackInfo.userdata, ‘none’) == 0
% ハイライト on
hilite_system(x);
hilite_system(lr_sub_j, ‘none’);
open_system(lr_sub_j);
else
% ハイライト off
hilite_system(x, ‘none’);
hilite_system(lr_sub_j, ‘none’);
end
end
end
end
end
すばらしい!
さっそく動かしてみましたが、まさにこういう事がやりたかったのです。ここのところ極端に時間がなかったので、とても助かります。
lr_subsystem = cellstr(lr_subsystem); のあたりとか、get_paramの戻り値が文字列になったりセル配列になったりするがために必要な対処ですよね。こういうのはSimulinkのいけない所だと思いますが、それにバッチリ対処がされていてすばらしいです。私はよくこの対処をしそこねる事があります;;
こうして動いているものを見ていると、だんだん欲が出てきますね。。。たとえばサブシステムのOutportからサブシステム外の信号線を見つけるとか。来週時間がとれそうなら、ちょっとチャレンジしてみます。時間がとれそうなら。。。
ありがとうございました。