Simulink建模助手系列-6【自动调整子系统高度和信号线】

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【批量对齐模块】

相关推荐
dracula0001 天前
Simulink建模助手系列-4【批量添加信号线】
matlab
dracula0001 天前
Simulink建模助手系列-5【批量对齐模块】
matlab
dracula0002 天前
Simulink建模助手系列-2【自动创建缺失的Goto】
matlab
Evand J2 天前
【UWB与IMU紧耦合定位,MATLAB例程】UWB的TOA定位方法,与IMU紧耦合,对目标轨迹定位并输出误差统计。适用于二维平面的高精度定位导航
开发语言·matlab·平面·uwb·组合导航
禁默2 天前
零基础全面掌握层次分析法(AHP):Python实现+论文加分全攻略
python·数学建模·matlab
软件算法开发2 天前
基于火烈鸟搜索算法的LSTM网络模型(FSA-LSTM)的一维时间序列预测matlab仿真
人工智能·rnn·matlab·lstm·一维时间序列预测·火烈鸟搜索算法·fsa-lstm
简简单单做算法3 天前
基于LSTM长短记忆网络模型的文本分类算法matlab仿真,对比GRU网络
matlab·分类·gru·lstm·文本分类
dracula0003 天前
通过get()函数获取Simulink模块的所有属性
matlab
dracula0003 天前
simulink建模助手系列-1【批量创建goto和from】
matlab