Simulinkブロックの置き換え

  • サンプル
  • ブロック置き換え
  • Fromブロックの追加・接続
model = 'test'
open_system(model);

blockName = 'NormalTimeReception'

add_line(model, [blockName,'/1'], [SwitchBlock,'/2'])

% Simulink モデル内の特定ブロックを Inport ブロックに置換するスクリプト
% MATLAB 2018b で動作確認

% ユーザーからモデル名を入力してもらう
function replaceBlock(modelName)

	load_system(modelName);

	% 置換対象の条件設定
	constantName = 'c_False';                 % Constantブロックのデータ
	unitDelayInitial = 'c_True';              % UnitDelayブロックの初期データ

	% 置換する Inport ブロックの詳細設定
	inportBaseName = 'NormalTimeReception';   % Inportブロック名の基本文字列
	inportDataType = 'Inherit: auto';         % Inportのデータ型
	inportWidth = 30;                         % Inportブロックの幅
	inportHeight = 14;                        % Inportブロックの高さ

	% 変更があったサブシステムを記録するリスト
	modifiedSubsystems = {};

	% モデル内のすべてのサブシステムを取得
	subsystems = find_system(modelName, 'BlockType', 'SubSystem');
	for i = 1:length(subsystems)
		currentSubsystem = subsystems{i};
		% サブシステム直下の Constant ブロックを取得
		constantBlocks = find_system(currentSubsystem, 'SearchDepth', 1, 'BlockType', 'Constant');
		for j = 1:length(constantBlocks)
			constantBlock = constantBlocks{j};
			% Constant ブロックの値が c_False か確認
			if strcmp(get_param(constantBlock, 'Value'), constantName)
				% Constant ブロックの出力ポートを取得し、接続先(Line)を確認
				constPorts = get_param(constantBlock, 'PortHandles');
				outLine = get_param(constPorts.Outport, 'Line');
				if outLine ~= -1
					dstBlocks = get_param(outLine, 'DstBlockHandle');
					if ~isempty(dstBlocks) && dstBlocks ~= -1
						for k = 1:length(dstBlocks)
							% 接続先ブロックが UnitDelay であるかチェック
							if strcmp(get_param(dstBlocks(k), 'BlockType'), 'UnitDelay')
								% UnitDelay の初期条件が c_True なら置換対象とする
								if strcmp(get_param(dstBlocks(k), 'InitialCondition'), unitDelayInitial)
									% UnitDelay ブロックの出力接続先情報を取得(削除前に記録)
									unitDelayPorts = get_param(dstBlocks(k), 'PortHandles');
									unitDelayOutLine = get_param(unitDelayPorts.Outport, 'Line');
									if unitDelayOutLine ~= -1
										unitDelayDstBlocks = get_param(unitDelayOutLine, 'DstBlockHandle');
										unitDelayDstPorts  = get_param(unitDelayOutLine, 'DstPortHandle');
									else
										unitDelayDstBlocks = [];
										unitDelayDstPorts  = [];
									end
									
									% 基準位置は Constant ブロックの位置を取得
									pos = get_param(constantBlock, 'Position');
									% 新規 Inport ブロック用の位置を再設定(幅30, 高さ14)
									newPos = [ pos(1), pos(2), pos(1)+inportWidth, pos(2)+inportHeight ];
									
									% 既存の接続ラインの削除
									delete_line(outLine);
									if unitDelayOutLine ~= -1
										delete_line(unitDelayOutLine);
									end
									
									% 対象ブロック(Constant, UnitDelay)の削除
									delete_block(constantBlock);
									delete_block(dstBlocks(k));
									
									% サブシステム内の既存 Inport ブロック数を取得し,
									% 新規ブロックのポート番号を(既存数+1)とする
									existingInports = find_system(currentSubsystem, 'SearchDepth', 1, 'BlockType', 'Inport');
									newPortNumber = length(existingInports) + 1;
									
									% サブシステム内の Inport ブロック名は "NormalTimeReception" とする
									newInportName = inportBaseName;
									newInportPath = [currentSubsystem, '/', newInportName];
									add_block('simulink/Sources/In1', newInportPath, ...
										'Position', newPos, ...
										'Port', num2str(newPortNumber), ...
										'OutDataTypeStr', inportDataType);
									
									% 元の接続先へ新 Inport ブロックからの接続を再設定
									if ~isempty(unitDelayDstBlocks) && unitDelayDstBlocks ~= -1
										for m = 1:length(unitDelayDstBlocks)
											% 接続先のブロック名とポート番号を取得し接続
											destBlockName = get_param(unitDelayDstBlocks(m), 'Name');
											destPortNum   = num2str(get_param(unitDelayDstPorts(m), 'PortNumber'));
											try
												add_line(currentSubsystem, [newInportName, '/1'], ...
													[destBlockName, '/2'], 'autorouting', 'on');
											catch
												warning('接続先の端子が既に使用されています: %s', destBlockName);
											end
										end
									end
									% 変更があったサブシステムを記録
									if ~ismember(currentSubsystem, modifiedSubsystems)
										modifiedSubsystems{end+1} = currentSubsystem;
									end
								end
							end
						end
					end
				end
			end
		end
	end

	% 変更があったサブシステムのみ背景色を設定 (状態:未適応)※下記3行のコメントアウトを外すことで色付け適応
	% for i = 1:length(modifiedSubsystems)
	% 	set_param(modifiedSubsystems{i}, 'BackgroundColor', 'cyan');
	% end

	% 変更内容を保存しシステムを閉じる (状態:処理完了後保村せず開く)
	open_system(modelName);
	% save_system(modelName);
	% close_system(modelName);
end

使い方👇

上記コードをコピーし、関数名称で保存(.mファイル)し、下記コマンドを実行

<関数名(ファイル名も同名)>('<モデルファイル名(拡張子なし)>')

例: replaceBlock('ForGesInfoCalcFunc_Calc')

function add_blocks_for_inputs(modelName)
    % Simulink モデルを開く
    load_system(modelName);
    
    % モデルのトップレベルのシステム名を取得
    topLevel = bdroot(modelName);
    
    % サブシステムを検索
    subsystems = find_system(modelName, 'BlockType', 'SubSystem');
    
    % 設定
    fromTag = 'NormalTimeReception'; % Fromブロックのタグ名
    fromBlockWidth = 175;            % Fromブロックの幅
    fromBlockHeight = 16;            % Fromブロックの高さ
    offsetX = -300;   % From ブロックの配置オフセット(左側)
    offsetY = 120;    % From ブロックの配置オフセット(下側)

    % 未接続ポートを格納するリスト
    unconnected_ports = {};

    % 各サブシステムを処理
    for i = 1:length(subsystems)
        subSys = subsystems{i};
        
        % サブシステムの入力ポートハンドルを取得
        inportHandles = get_param(subSys, 'PortHandles');
        
        if isfield(inportHandles, 'Inport')
            for j = 1:length(inportHandles.Inport)
                portHandle = inportHandles.Inport(j);
                
                % 接続状態を取得
                lineHandle = get_param(portHandle, 'Line');
                
                % 未接続のポートを検出
                if lineHandle == -1
                    % サブシステムの親階層(外部)を取得
                    parentSystem = get_param(subSys, 'Parent');
                    if isempty(parentSystem)
                        parentSystem = topLevel;
                    end

                    % Fromブロックの一意な名前を生成
                    existingFromBlocks = find_system(parentSystem, 'SearchDepth', 1, 'BlockType', 'From');
                    fromBlockName = sprintf('From_%d', length(existingFromBlocks) + 1);
                    
                    % ポートの位置を取得
                    pos = get_param(subSys, 'Position');
                    y = pos(2) + (j - 1) * 40 + offsetY; % 位置を調整

                    % Fromブロックを追加(外部に作成)
                    fromBlockPath = sprintf('%s/%s', parentSystem, fromBlockName);
                    if isempty(find_system(parentSystem, 'SearchDepth', 1, 'Name', fromBlockName))
                        add_block('simulink/Signal Routing/From', ...
                            fromBlockPath, ...
                            'Position', [pos(1) + offsetX, y - fromBlockHeight/2, pos(1) + offsetX + fromBlockWidth, y + fromBlockHeight/2], ...
                            'GotoTag', fromTag, ...
                            'ShowName', 'off'); % ブロック名を非表示
                    end

                    % From ブロックをサブシステムの Inport に接続
                    fromPortHandle = get_param(fromBlockPath, 'PortHandles');
                    add_line(parentSystem, fromPortHandle.Outport, portHandle, 'autorouting', 'on');

                    % ログ出力
                    unconnected_ports{end+1} = sprintf('Added From block for: %s (Port %d)', subSys, j);
                end
            end
        end
    end

    % 結果を出力
    if isempty(unconnected_ports)
        fprintf('No unconnected input ports found.\n');
    else
        fprintf('From blocks added for the following unconnected input ports:\n');
        for k = 1:length(unconnected_ports)
            fprintf('%s\n', unconnected_ports{k});
        end
    end

	% 変更内容を保存しシステムを閉じる (状態:処理完了後保村せず開く)
	open_system(modelName);
	% save_system(modelName);
	% close_system(modelName);
end

使い方👇

上記コードをコピーし、関数名称で保存(.mファイル)し、下記コマンドを実行

<関数名(ファイル名も同名)>('<モデルファイル名(拡張子なし)>')

例: add_blocks_for_inputs('ForGesInfoCalcFunc_Calc')

タイトルとURLをコピーしました