Simulink建模助手系列-6
功能介绍
Simulink建模有时子系统Subsystem的大小不合适导致输入输出显得很拥挤或很空旷,另外子系统的输入输出端口关联的模块不对齐,即信号线不是直的,看起来比较乱、不美观。该功能主要用于自动根据端口的数量调整子系统的高度,并对齐输入输出关联模块,拉直信号线。因为有时关联模块不止一个,可能还串联了其他模块,因此希望对齐功能需要具有一定的传递性,整个链路上的模块都对齐。该功能除了可用于Subsystem外,还可以通过预设模块集合添加适用的模块类型。
实现效果如下:
自动调整子系统
实现方法
为了实现这个功能,涉及的内容主要有:
- 根据预设模块的类型获取选中的模块。
- 逐个修改选中模块的高度。
- 逐个对齐选中模块端口的输入输出关联模块。
为了使对齐具有传递性,对齐时采用递推的方式。
实现该功能的主要流程如下:

递推对齐算法的主要流程:

主要代码
有些函数如果在之前的文章中已经进行了介绍,这里就仅简单说明下用来干什么。
1)获取选中的预设类型的模块
matlab
% 预设的模块类型
block_types = {
'SubSystem','Scope','ModelReference', ...
'Mux','Demux', ...
'BusSelector','BusCreator', ...
'Sum','Product','MultiPortSwitch', ...
'Merge','Switch','SwitchCase', ...
'RelationalOperator','Logic', ...
};
% 获取选中的指定类型的模块
blocks = getSelectedBlock(gcs, block_types);
matlab
% 自定义函数:获取选中的指定类型的模块
function selectedBlock = getSelectedBlock(current_system,block_types)
selectedBlock = [];
for i = 1:length(block_types)
selectedBlock_i = find_system(current_system, ...
'SearchDepth', 1, ...
'Selected', 'on', ...
'BlockType', block_types{i});
end
if isempty(selectedBlock_i)
continue
end
if strcmpi(selectedBlock_i{1},current_system)
selectedBlock_i = selectedBlock_i(2:end);
end
selectedBlock = [selectedBlock;selectedBlock_i];
end
通过预设模块类型管理该功能对哪些类型的模块适用。利用find_system()函数将选中的在预设类型里的模块筛选处理。因为会经常用到获取选中的指定类型的模块,所以将该这部分代码进行封装。
2)逐个调整模块的高度
matlab
% 逐个处理
block_i = blocks{i};
% 获取输入输出端口的数量,取大计算最小高度
blk_pos = get_param(block_i,'position');%获取尺寸
blk_ports = get_param(block_i, 'PortHandles'); % 获取端口
inports = blk_ports.Inport; % 输入端口集合
outports = blk_ports.Outport; % 输出端口集合
max_num = max(length(inports),length(outports));
max_num = max(max_num,1);
min_height = max_num*36+6;
% 计算当前高度,如果最小高度大于当前高度,则调整子系统的高度
old_height = abs(blk_pos(4)-blk_pos(2));
if min_height>old_height
blk_pos(4) = blk_pos(2)+min_height;
set_param(block_i, 'position', blk_pos);
end
这里主要是如何获取输入端口和输出端口,以及如何根据端口数量计算合适的高度。最后通过set_param()函数更新子系统的高度。
3)分别对齐每个输入和输出端口的关联模块
matlab
blk_ports = get_param(block_i, 'PortHandles'); % 获取端口数
inports = blk_ports.Inport;
outports = blk_ports.Outport;
% 对齐输入端信号线
alignBlockLine(inports,1);
% 对齐输出端信号线
alignBlockLine(outports,2);
matlab
% 自定义函数:批量对齐模块输入输出端口的信号线
function alignBlockLine(ports, port_type)
% ports = inports;
% port_type =
% 1: inport, 对齐SrcBlock
% 2:outport, 对齐DstBlock
blk_bhs_list = [-1];
for j = 1:length(ports)
port_i = ports(j);
% 获取信号线
line_handle = get_param(port_i, 'Line');
if line_handle==-1
continue
end
line_points = get_param(line_handle, 'Points');
switch port_type
case {1,'inport','input'}
port_type_str = 'Inport';
% 获取线左侧的block
blk_bhs = get_param(line_handle, 'SrcBlockHandle');
y_old = line_points(1,2);
y_new = line_points(end,2);
% 一个输入模块有多个信号线分支
line_parent = get_param(line_handle,'LineParent');
if ~isempty(line_parent) && line_parent~=-1
line_points_rep = get_param(line_parent, 'Points');
y_old = line_points_rep(1,2);
end
case {2,'outport','output'}
port_type_str = 'Outport';
blk_bhs = get_param(line_handle, 'DstBlockHandle');
y_old = line_points(end,2);
y_new = line_points(1,2);
% 一个输出端口有多个信号线分支
line_child = get_param(line_handle,'LineChildren');
if ~isempty(line_child)
y_olds = [];
for ci = 1:length(line_child)
line_points_rep = get_param(line_child(ci), 'Points');
y_olds(end+1) = line_points_rep(end,2);
end
y_old = sort(y_olds);
end
end
if any(ismember(blk_bhs_list,blk_bhs)) % 避免重复调整
continue
end
blk_bhs_list = [blk_bhs_list;blk_bhs];
% 逐个调整端口关联模块的位置,并对关联模块的端口进行递推对齐。
blk_bhs = sortBlocks(blk_bhs); % 调用自定义函数对模块从上到下进行排序
for jj = 1:length(blk_bhs) % 一个输出端口对应多个输出模块时为多个
blk_bh = blk_bhs(jj);
if strcmpi(get_param(blk_bh,"BlockType") ,'subsystem')
% 如果关联的模块是子系统,并且有多于2个端口时不继续处理
if size(get_param(blk_bh,"PortConnectivity"),1)>2
continue
end
end
blk_pos = get_param(blk_bh, 'Position');
% 兼容多输出的情况
blk_pos(2) = blk_pos(2) - y_old(jj) + y_new + (jj-1)*42;
blk_pos(4) = blk_pos(4) - y_old(jj) + y_new + (jj-1)*42;
set_param(blk_bh, 'Position',blk_pos);
% -- 递推处理关联模块的对齐 --
tmp_ports = get_param(blk_bh, 'PortHandles'); % 获取关联模块的端口
for kk = 1:length(tmp_ports)
tmp_port_i = tmp_ports(kk);
alignBlockLine(tmp_port_i.(port_type_str), port_type);
end
end
end
end
这部分主要是需要逐个处理端口连接链路上各模块的对齐问题,这里采用递推的方式。以端口集合为入口,通过端口对应的信号线定位到与其相连的关联模块,从而对关联模块的位置进行调整,使信号线变成水平拉直的状态。对于信号线有分支的情况, 找到关联模块对应的信号线,并获取相关的位置信息。其中用到的模块排序函数sortBlocks(),可详见《Simulink建模助手系列-4》
系列文章
Simulink建模助手系列-1【批量创建Goto和From】
Simulink建模助手系列-2【自动创建缺失的Goto】
Simulink建模助手系列-3【批量创建Inport和Outport】
Simulink建模助手系列-4【批量添加信号线】
Simulink建模助手系列-5【批量对齐模块】