主要内容

使用命令行API在需求编辑器中记录Simulink模型金宝app

这个例子使用了Simulink®和S金宝appimulink Requirements®api来自动捕获和链接Simulink模型结构,目的是在Simulink Requirements Editor中记录设计。在替换或修改链接的工件之后,自动化还将帮助修复或迁移需求跟踪数据。演示了以下命令行api的使用:

在一些地方,我们也使用了传统rmi从已退役的SLVnV产品的需求管理接口(RMI)部分继承的api。

用例1:在Simulink需求中链接Simu金宝applink模型代理

您希望使用Simulink Requir金宝appements产品来创建Simulink设计的详细描述,并且希望在与Simulink模型相匹配的层次结构中组织需求集合。您还需要一种简单的方法来在Requirements集合的项和设计中相应的元素之间导航。

为了这个演示的目的,请考虑slvnvdemo_powerwindow_vs.slx为验证的功能属性而设计的规范模型slvnvdemo_powerwindowController.slx

open_system (“slvnvdemo_powerwindow_vs”);open_system (“slvnvdemo_powerwindowController”);

我们使用传统的VNV/RMI产品API,rmi (getObjectsInModel,模型),以获取对象的分层列表模型,然后使用Simuli金宝appnk Requirementsslreq。* api自动生成每个Simulink模型的代理(表示)。金宝app

然后,我们可以在自动生成的代理项的Description或Rational字段中提供相关的设计需求信息。

下面是用两个模型代理构建一个需求集的脚本。下面的三个命令提供了如何以编程方式填充的示例描述字段,但最可能的情况是,您将在编辑器中以交互方式执行此操作。

模型= {“slvnvdemo_powerwindow_vs”“slvnvdemo_powerwindowController”};workDir = tempname;disp ([“使用”workDir'存储生成的文件。']);
使用C:\Users\ahoward\AppData\Local\Temp\tp048cdc5c_b22d_44f6_bb6c_85d54e962505存储生成的文件。
mkdir (workDir);目录(workDir);modelIdx = 1:length(models)reqSetFile = fullfile(workDir, [modelName .]“.slreqx”]);slProxySet = slreq.new (reqSetFile);用匹配的名称创建单独的ReqSet文件open_system (modelName);%将为这个Simulink模型中的每个对象创建一个代理项金宝appmodelNode = slProxySet.add (“Id”modelName,“摘要”, (modelName“描述”]);[objh, parentIdx, isSf, sid] = rmi(“getobjectsInModel”, modelName);objIdx = 1:长度(objHs)如果parentIdx (objIdx) < 0顶级项目是模型本身indexedReqs (objIdx) = modelNode;% #好< SAGROW >其他的parentReq = indexedReqs (parentIdx (objIdx));如果isSf(objIdx) sfObj = 金宝appSimulink.ID. isSf(objIdx)getHandle ([modelName SIDs {objIdx}]);如果isa (sfObj“Stateflow。国家的) name = sf(“得到”objHs (objIdx),' . name ');elseifisa (sfObj“Stateflow。过渡的) name = sf(“得到”objHs (objIdx),“.labelString”);其他的警告('跳过类型为%s的SF对象。'类(sfObj));继续结束类型= strrep(类(sfObj),“Stateflow”。'');其他的name = get_param (objHs (objIdx),“名字”);类型= get_param (objHs (objIdx),“BlockType”);结束indexedReqs (objIdx) = parentReq.add (...“Id”SIDs {objIdx},“摘要”(姓名“(”类型“)”]);% #好< SAGROW >结束结束slProxySet.save ();%保存自动生成的需求集结束slreq.editor ();%打开编辑器以查看构造的需求集slProxySet = slreq.find (“类型”“ReqSet”“名字”“slvnvdemo_powerwindow_vs”);roItem = slProxySet.find (“类型”“要求”“摘要”《乌利希期刊指南(尺寸));%将…%提供此项目的描述文本roItem。描述= [“如果……司机的UP按钮应该会一直关闭车窗。”...“在0.5秒内释放”];

创建模型对象和代理项之间的可跟踪性

现在我们可以在需求编辑器中浏览每个模型的结构,并且我们可以编辑Description字段以提供关于每个设计元素的额外细节。缺少的是在Simulink图中的对象和Simulink Requirements中的代理/代理项之间导航的简单方法。金宝app下面的脚本演示了使用slreq.createLinkAPI来自动添加导航链接。我们可以选择任何想要的粒度级别。出于本例的目的,我们将限制对子系统块的链接。

我们还可以启用突出显示来可视化哪些Simulink对象接收了导航链接。金宝app

在Simulink块中导航链接,查看Simul金宝appink Requirements Editor中相应的代理项。中的关联块的超链接细节窗格下链接在右下方。

modelIdx = 1:length(models)counter = 0;slProxySet = slreq.find (“类型”“ReqSet”“名字”, modelName);proxyItems = slProxySet.find (“类型”“要求”);reqIdx = 1:numel(proxyItems) roItem = proxyItems(reqIdx);如果包含(roItem。总结,“(子系统)”% | |包含(roItem。总结,“(国家)”)sid = [modelName roItem.Id];disp ([“链接”sid“. .”]);srcObj = 金宝appSimulink.ID.getHandle (sid);链接= slreq。创建(srcObj roItem);链接。描述=“slreq代理项目”;Counter = Counter + 1;结束结束disp ([“创建”num2str(柜台)“链接”modelName]);rmi (“highlightModel”, modelName);结束
连接slvnvdemo_powerwindow_vs: 394 . .连接slvnvdemo_powerwindow_vs: 394:224 . .连接slvnvdemo_powerwindow_vs: 394:272 . .连接slvnvdemo_powerwindow_vs: 394:271 . .连接slvnvdemo_powerwindow_vs: 394:360 . .连接slvnvdemo_powerwindow_vs: 397 . .连接slvnvdemo_powerwindow_vs: 397:107 . .连接slvnvdemo_powerwindow_vs: 397:300 . .连接slvnvdemo_powerwindow_vs: 397:108 . .连接slvnvdemo_powerwindow_vs: 397:285 . . linking slvnvdemo_powerwindow_vs:397:307 .. linking slvnvdemo_powerwindow_vs:399 .. linking slvnvdemo_powerwindow_vs:399:650 .. linking slvnvdemo_powerwindow_vs:399:214 .. linking slvnvdemo_powerwindow_vs:399:218 .. linking slvnvdemo_powerwindow_vs:399:273 .. linking slvnvdemo_powerwindow_vs:160 .. linking slvnvdemo_powerwindow_vs:160:643 .. linking slvnvdemo_powerwindow_vs:160:646 .. linking slvnvdemo_powerwindow_vs:160:590 .. linking slvnvdemo_powerwindow_vs:160:591 .. linking slvnvdemo_powerwindow_vs:160:648 .. linking slvnvdemo_powerwindow_vs:160:592 ..
为slvnvdemo_powerwindow_vs创建23个链接
连接slvnvdemo_powerwindowController: 39 . .连接slvnvdemo_powerwindowController: 40 . .连接slvnvdemo_powerwindowController: 36 . .
为slvnvdemo_powerwindowController创建了3个链接

用例2:在替换链接的目标工件之后重用现有链接

在设计项目开发过程中,可能需要迁移到一组新的需求。如果当前的需求有链接,并且当有一个已知的规则将原始链接的需求与新的需求集中相应的条目相关联时,您可能想要在可能的地方自动迁移链接,以避免手动重做所有的链接。迁移现有链接比重新创建新链接更好,因为您保留了现有的元数据,如关键字、理由语句、评论历史。

为了快速构建一个可能需要迁移链接的示例情况,我们将从从Microsoft Word文档导入的Requirements开始,然后创建一些链接。

然后,我们创建一些链接,可以是交互式的(通过在Requirements Perspective模式下的拖放),也可以使用API,以允许在Simulink对象和导入的需求之间导航。金宝app

Simulink对象的导航可以通金宝app过上下文菜单完成,也可以在Requirements Perspective模式下单击。

examplesFolder = fullfile (matlabroot,“工具箱”“slrequirements”“slrequirementsdemos”);docsFolder = fullfile (examplesFolder,“powerwin_reqs”);目录(docsFolder);%以防万一externalDocName =“PowerWindowSpecification”;externalDoc = fullfile(docsFolder, [externalDocName . txt]“。docx”]);outputFile = fullfile (workDir,“ReadOnlyImport.slreqx”);[~, ~, roReqSet] = slreq.import (externalDoc,“ReqSet”, outputFile);%没有额外的…%参数默认的导入模式是“只读引用”roReqSet.save ();roItem = roReqSet.find (“CustomId”“金宝appSimulink_requirement_item_2”);designModel =“slvnvdemo_powerwindowController”;link1 = slreq.createLink ([designModel“/真值表”), roItem);%链接到只读项…导入集的%link2 = slreq.createLink ([designModel' /真理Table1 '), roItem);链接第2块到…%相同的只读项slreq.show (link1.source ());%突出第一个链接的来源slreq.show (link1.destination ());%导航到第一个链接的目标rmi (“视图”, (designModel' /真理Table1 '), 2);% navigation 2nd link from Truth Table1…%使用遗留的RMI('视图')API

更新导航到可选导入需求集的链接

注意,我们导入的Word文档是“只读引用”,这是默认值slreq.import命令在不带可选参数的情况下运行。此导入模式允许在源文档的新版本可用时更新所导入的项。现在,假设我们改变了想法:我们希望导入的项在Simulink Requirements Editor中是完全可编辑的,包括添加、删除和结构移动。金宝app虽然您可以解锁和编辑“作为引用”导入的项目的属性,但您不能重新排序导入的项目或添加新的项目,如果您删除了一个项目,它将在执行下一步时重新出现更新从修改的外部文档。当需要无限制的编辑功能时,我们使用不同的导入模式:“作为可编辑需求”,通过提供附加的AsReference论点的slreq.import命令,并指定的价值。

这将生成一个新的需求集,仅在Simulink需求中进行管理。金宝app与原始外部文档没有连接,您可以根据需要自由地添加/移动/删除条目。现在,您不需要解锁导入的项目来修改描述或其他属性:

然而,有一个问题:我们先前创建的链接从Simulink连接到原始的只读引用,而不是最近导入的可编辑的需求。金宝app解决方案是创建并运行一个脚本,该脚本将现有链接重定向到新导入(可编辑)集中的相应项。我们使用setDestinationAPI来执行所需的更新。

在循环链接集中的所有链接并调整受影响的链接以与相应的可编辑项连接后,当我们从模型块导航时,可编辑集中的正确项将打开,并显示来自两个块的传入链接。

下面是完成此任务的示例脚本。

outputFile = fullfile (workDir,“EditableImport.slreqx”);%重新导入为可编辑的需求[~, ~, mwReqSet] = slreq.import (externalDoc,“ReqSet”outputFile,“作为参考”、假);mwReqSet.save ();linkSet = slreq.find (“类型”“LinkSet”“名字”, designModel);% LinkSet用于我们的设计模型链接= linkSet.getLinks ();%此链接集中的所有外发链接updateCount = 0;linkIdx = 1:numel(links) link = links(linkIdx);如果比较字符串(link.destination.reqSet [roReqSet。的名字“.slreqx”])%如果这个链接指向…%在只读的ReqSet中sid = link.destination.sid;%链接只读项的内部标识符roItem = mwReqSet.find (“席德”sid);找到链接的只读项id = roItem.Id;%导入的只读项的文档端标识符mwItem = mwReqSet.find (“Id”、身份证);%在编辑器中找到匹配的项目%的要求设置link.setDestination (mwItem);updateCount = updateCount + 1;结束结束disp ([“更新”num2str (updateCount)“链接来自”designModel]);
更新slvnvdemo_powerwindowController的2个链接
slreq.show (link.destination ());%检查最近更新的目的地…%我们修改的链接rmi (“视图”, (designModel' /真理Table1 '), 2);%再次导航(遗留API),可编辑…在RE中选择的%项目

用例3:替换源对象后重用现有的传出链接

考虑这样一种情况:您有一个子系统,它有许多到需求的链接,并且这个子系统需要重新设计或完全替换。新的实现基本上是类似的,并且您希望尽可能保留现有的链接(具有相同名称的块存在于模型结构层次结构的同一层)。这将允许将手动链接步骤限制为原始实现中不存在的块。你使用setSourceAPI用于在替换子系统之后在新源对象上重新附加现有链接。请注意,您不能简单地继续使用旧的链接,因为链接依赖于惟一持久的独立会话标识符(sid)来关联链接源对象(“拥有”链接的Simulink对象),而替换的子系统为每个对象都有新的sid。金宝app

演示…的用法setSource使用我们的示例模型,我们将简单地用相同的新块替换上一节中链接的两个真值表块。一旦这样做了,链接就变成了未解决的,因为新的真值表副本有新的sid。

在需求编辑器中,单击显示链接注意橙色的三角形表示所有断开的链接。一共有4个,因为每个被替换的块都有2个链接:一个链接到中的代理项slvnvdemo_powerwindowController.slreqx和另一个链接到导入的需求ReadOnlyImport.slreqx

slreq.open (“slvnvdemo_powerwindowController.slreqx”
ans = ReqSet with properties: Description: " Name: 'slvnvdemo_powerwindowController' Filename: 'C:\Users\ahoward\AppData\Local\Temp\tp048cdc5c_b22d_44f6_bb6c_85d54e962505\slvnvdemo_powerwindowController. "slreqx' Revision: 1 Dirty: 0 CustomAttributeNames: {} CreatedBy: 'ahoward' CreatedOn: 14-Jan-2021 15:22:27 ModifiedBy: 'ahoward' modifieddon: 14-Jan-2021 15:22:27

originalModel =“slvnvdemo_powerwindowController”;updatedModel =“UpdatedModel”;save_system (originalModel fullfile (workDir [updatedModel“.slx”)));%这也会创建…% .slmx文件在workDirdelete_line (updatedModel“Mux1/1”“真值表/ 1”);断开原始块delete_line (updatedModel“真值表/ 1”“控制/ 3”);断开原始块add_block ([updatedModel“/真值表”]、[updatedModel' /新真值表]);%创建…%替代块delete_block ([updatedModel“/真值表”]);删除原始块add_line (updatedModel“Mux1/1”“新真值表/ 1”);%重新连接新块add_line (updatedModel“新真值表/ 1”“控制/ 3”);%重新连接新块set_param ([updatedModel' /新真值表],“名字”“真值表”);%恢复原始名称delete_line (updatedModel“Mux4/1”“真理Table1/1”);断开原始块delete_line (updatedModel“真理Table1/1”“控制/ 4”);断开原始块add_block ([updatedModel' /真理Table1 ']、[updatedModel' /新真理Table1 ']);%创建…%替代块delete_block ([updatedModel' /真理Table1 ']);删除原始块add_line (updatedModel“Mux4/1”“新真理Table1/1”);%重新连接新块add_line (updatedModel“新真理Table1/1”“控制/ 4”);%重新连接新块set_param ([updatedModel' /新真理Table1 '],“名字”“真理Table1”);%恢复原始名称

更新源端以修复损坏的链接

现在我们需要遍历新模型中的所有链接,识别那些使用未解析源的链接isResolvedSourceAPI,然后使用setSource命令来修复每个损坏的链接。由于我们不能依靠旧的sid找到所需的链接新源,所以我们打开原始模型,发现原始块的路径和名称,然后在更新的模型中找到相应的替换块。

参见下面的示例脚本。当你运行这个脚本时,它报告了4个固定的链接。检查Simulink Requirements 金宝appEditor中的Links视图,并确认所有链接现在都已解决,任何地方都没有橙色图标指示器。

open_system (originalModel);updatedLinkSet = slreq.find (“类型”“LinkSet”“名字”, updatedModel);链接= updatedLinkSet.getLinks ();fixCount = 0;linkIdx = 1:numel(links) link = links(linkIdx);如果~link.isResolvedSource() missingSID = link.source.id;origBlockHandle = 金宝appSimulink.ID。getHandle ([originalModel missingSID]);origBlockPath = getfullname (origBlockHandle);[~, blockPath] = strtok (origBlockPath,' / ');updatedBlockPath = [updatedModel blockPath];updatedModelSID = 金宝appSimulink.ID.getSID (updatedBlockPath);updatedBlockHandle = 金宝appSimulink.ID.getHandle (updatedModelSID);link.setSource (updatedBlockHandle);fixCount = fixCount + 1;结束结束updatedLinkSet.save ();disp ([“固定”num2str (fixCount)“链接在”updatedModel“.slmx”]);
修正了UpdatedModel.slmx中的4个链接

清理

在执行上述步骤后,为了进行清理,我们关闭所有模型并删除本例中脚本创建的所有文件。slreq.clear命令将从MATLAB会话内存中删除所有Requirements和Links数据,以避免与您接下来要做的冲突。

slreq.clear ();bdclose (“所有”);rmpath (workDir);rmpath (docsFolder);删除目录(workDir“年代”);为我们的文档清除存储的导入位置,以避免在重新运行时提示slreq.import.docToReqSetMap (externalDoc“清楚”);