Simulink建模助手系列-进阶2
- 功能介绍
- [1. 总线信号信息的获取](#1. 总线信号信息的获取)
- [2. 信号层次结构的解析](#2. 信号层次结构的解析)
- [3. 利用结构树展示结果](#3. 利用结构树展示结果)
- [4. 完整的示例代码](#4. 完整的示例代码)
- 系列文章
-
- [- 基础篇:](#- 基础篇:)
- [- 进阶篇:](#- 进阶篇:)
功能介绍
本文主要分享如何对Bus模块的总线信号层级进行解析,Simulink本身有个类似的功能,如图1所示。本文主要介绍如何通过代码的方式实现相似的功能,之所以需要实现该功能,主要是为了具备解析Bus模块总线信号的能力,为后续实现一些关联功能提供基础(如根据总线信号的解析结果自动创建相关的数据字典、统计某个子系统中用到了总线中的哪些信号等)。

图1 Simulink的信号层次结构查看功能
本文实现的效果如图2所示。除了可以通过信号线解析,还可以通过Bus Creator和Bus Selector解析。增加对总线的子信号和子总线数量的显示。

图2 本文实现的信号层次结构解析效果
下面主要介绍如何获取总线的信号信息,如何解析总线信号的层次结构,如何通过结构树的方式展示信号的层次结构。
1. 总线信号信息的获取
有两种方式可以获取总线的信号信息:一种是通过Bus Selector 的InputSignals属性,如图3所示。这种方式比较简单,但是只适用于Bus Selector模块,局限性较大。

图3 Bus Selector的InputSignals属性的值
另一种是通过端口句柄的SignalHierarchy属性,关于SignalHierarchy属性的结果和值的形式如图4(a)和图4(b)所示。该方法相对更复杂,但适用性广,本文主要介绍此方法。
图4(a) 关于SignalHierarchy的帮助说明

图4(b) 端口的SignalHierarchy属性的值
为了获取SignalHierarchy属性,需要获取相应的端口句柄,对于信号线,需要获取的是来源端口;对于Bus Creator,获取的是输出端口;对于Bus Selector,获取的是输入端口。以下是主要的代码。
matlab
% 自定义函数:根据block的port获取信号层次信息
function sh = getSignalHierarchy(myblock)
% 获取选中元素的类型
type = get_param(myblock,'Type');
% 获取选中元素的句柄
myblock_handle = get_param(myblock,'Handle');
% 根据不同的元素类型,选择不同的端口获取方法
switch type
case {'block'} % 对于不同的模块类型,选择不同的端口获取方法
blocktype = get_param(myblock,'BlockType');
switch blocktype
case {'BusCreator'}
port_h = get_param(myblock_handle,'PortHandles');
port_h = port_h.Outport;
case {'BusSelector'}
port_h = get_param(myblock_handle,'PortHandles');
port_h = port_h.Inport;
otherwise
return
end
case {'line'}
port_h = get_param(myblock_handle,'SrcPortHandle');
otherwise
return
end
2. 信号层次结构的解析
SignalHierarchy属性获取的总线信号层次如图4(b)所示,总线的信号信息包含在Children里,里面是多维的struct结构,其中SignalName是子信号的名称,如果子信号是总线时,其Children非空,包含的是其子信号,结构与本层的信号结构一致,可以发现这是一个嵌套的数据结构。本文的解析主要是需要将其平展开,对子信号是单信号还是总线信号进行区分,得到总线类型信号的集合及其所包含的子信号信息,如图5所示。这么做的目的是为了后续生成数据字典做准备。

图5 信号层次结构解析后的结果
因为SignalHierarchy属性的值是嵌套的形式,为了解析,本文采用递归的方式,逐级对Children的内容进行解析和整理。主要代码如下:
matlab
% 自定义函数:递归解析信号层次结构
function bus_set = parseSignalHierarchy(sh, sig_parent)
sig_children = sh.Children;
bus_set = []; %bus集合
sigs = []; %当前bus的子信号列表
for i = 1:length(sig_children)
l_sh = sig_children(i);
l_name = l_sh.SignalName;
l_children = l_sh.Children;
% 构造数据
l_sig_parent = sprintf('%s.%s',sig_parent,l_name);
i_sig = struct();
i_sig.sigName = l_name;
i_sig.sigType = 'var';
i_sig.sigPath = l_sig_parent;
% 判断是否为bus
if ~isempty(l_children) % 非空,是bus
i_sig.sigType = 'bus';
l_bus_set = parseSignalHierarchy(l_sh,l_sig_parent); % 递归
bus_set = [bus_set;l_bus_set]; % 搜集总线集合
end
sigs = [sigs;i_sig]; %构造信号的集合
end
% 构造结果
t_bus = struct();
busNames = strsplit(sig_parent,'.');
t_bus.busName = busNames{end};
t_bus.busSigs = sigs;
bus_set = [t_bus; bus_set];
end
3. 利用结构树展示结果
根据SignalHierarchy属性的值创建结构树展示信号层次结构同样采用递归的方式,效果如图2所示。主要代码如下:
matlab
% 自定义函数:递归解析信号层次结构生成结构树
function [num_var, num_bus] = treeSignalHierarchy(sh, tree_node)
sig_children = sh.Children;
num_var = 0; % 单信号个数
num_bus = 0; % 子总线个数
for i = 1:length(sig_children)
l_sh = sig_children(i);
l_name = l_sh.SignalName;
l_children = l_sh.Children;
% 增加节点
l_tree_node = uitreenode(tree_node,'Text',l_name);
% 判断是否为bus
if ~isempty(l_children) % 非空,是bus: bus+1
num_bus = num_bus+1;
[l_num_var, l_num_bus] = treeSignalHierarchy(l_sh,l_tree_node); % 递归
num_var = num_var+l_num_var;
num_bus = num_bus+l_num_bus;
else % 是var:num_var+1
num_var = num_var+1;
end
end
if num_var + num_bus>0
tree_node.Text = sprintf( ...
'%s (子信号:%d, 子总线:%d)',tree_node.Text,num_var,num_bus);
end
end
最后,额外说明下,为了能够获取选中的信号线,使用find_system()函数时需要使'FindAll = on',代码如下所示。加上此设置后find_system返回的是句柄值。
matlab
selectedLine_h = find_system(gcs, ...
'FindAll', 'on', ...
'SearchDepth', 1, ...
'Type','line', ...
'Selected', 'on');
4. 完整的示例代码
以选中信号线为例。
matlab
% 构造界面
h_fig = uifigure('Name','信号层次结构解析结果(示例)');
ly_main = uigridlayout(h_fig,'RowHeight',{'1x'},'ColumnWidth',{'1x'});
tree_sigs = uitree(ly_main);
% 选中信号线
myblocks = find_system(gcs, ...
'FindAll', 'on', ...
'SearchDepth', 1, ...
'Type','line', ...
'Selected', 'on');
bus_sets = {};
for i = 1:length(myblocks)
myblock = myblocks(i);
% 获取信号信息
sh = getSignalHierarchy(myblock);
% 解析信号,返回总线类信号集合
bus_set = parseSignalHierarchy(sh, '0');
bus_sets{end+1,1} = bus_set;
% 解析信号,生成结构树
parent = uitreenode(tree_sigs,'Text',sprintf('%d: ###',i));
treeSignalHierarchy(sh, parent);
end
% 全部展开
expand(tree_sigs,'all');
PS:可将这部分代码进一步封装成回调函数,集成到主界面里。
实现后的效果如下:
信号层次结构解析与显示
系列文章
- 基础篇:
Simulink建模助手系列-1【批量创建Goto和From】
Simulink建模助手系列-2【自动创建缺失的Goto】
Simulink建模助手系列-3【批量创建Inport和Outport】
Simulink建模助手系列-4【批量添加信号线】
Simulink建模助手系列-5【批量对齐模块】
Simulink建模助手系列-6【自动调整子系统高度和信号线】