使用可变子系统生成使用 C 预处理器条件句的代码
此示例说明如何使用 Simulink® 可变子系统生成 C 预处理器条件句,这些条件句控制可变子系统的哪个子级子系统在 Simulink Coder™ 生成的代码中处于激活状态。
可变子系统概述
Variant Subsystem 模块包含两个或更多子级子系统,其中一个子级子系统在模型执行期间处于激活状态。激活的子级子系统称为活动变体。您可以通过编程方式在基础工作区中更改变量值来切换可变子系统模块的激活变体,或通过手动方式在可变子系统模块对话框中覆盖变体选择来进行切换。在模型编译期间,激活变体由 Simulink 通过编程方式连接到可变子系统的输入端口和输出端口模块。
为了以编程方式控制变体选择,在 Variant Subsystem 模块对话框中将每个子级子系统与一个 Simulink.Variant
对象相关联。Simulink.Variant
对象在 MATLAB® 基础工作区中创建。这些对象具有一个名为 Condition
的属性,它是一个计算结果为布尔值的表达式,用于确定激活的可变子级子系统。
默认情况下,生成的代码只包含活动变体。您也可以参数化激活变体的选择,并使其依赖于 MATLAB 基础工作区中变量和对象的值。当您生成代码时,您可以生成所有变体的代码,并延迟选择激活变体,直到需要编译该代码时再选择。
指定子系统模块的变体
打开示例模型 PreprocessorConditionalsUsingVariantSubsystem
会运行在“ModelProperties > Callbacks”对话框中定义的 PostLoadFcn。这会在基础工作区中添加用于 Variant Subsystem 模块的变量。
open_system('PreprocessorConditionalsUsingVariantSubsystem')
LeftController 可变子系统包含两个子级子系统:Linear 和 Nonlinear。当 Simulink.Variant 对象 LINEAR 的计算结果为 true
时,LeftController/Linear 子级子系统执行;当 Simulink.Variant 对象 NONLINEAR 的计算结果为 true
时,LeftController/Nonlinear 子级子系统执行。
通过右键点击 LeftController 子系统并选择 Subsystem Parameters
(这将打开 LeftController 子系统模块对话框),为 LeftController 子系统指定 Simulink.Variant 对象。
open_system('PreprocessorConditionalsUsingVariantSubsystem/LeftController');
LeftController 子系统模块对话框使用基础工作区中存在的两个 Simulink.Variant 对象 LINEAR
和 NONLINEAR
创建 Linear 与 Nonlinear 子系统之间的关联。这些对象具有一个名为 Condition
的属性,它是一个计算结果为布尔值的表达式,用于确定激活变体子级子系统(Linear 或 Nonlinear)。条件也显示在子系统模块对话框中。在此示例中,LINEAR
和 NONLINEAR
的条件分别为 'VSSMODE == 0' 和 'VSSMODE == 1'。
在此示例中,Simulink.Variant 对象在基础工作区中创建。
LINEAR = Simulink.Variant; LINEAR.Condition = 'VSSMODE==0'; NONLINEAR = Simulink.Variant; NONLINEAR.Condition = 'VSSMODE==1';
指定变体控制项变量
变体对象允许您在整个模型中重用任意复杂的条件。多个 Variant Subsystem 模块可以使用相同的 Simulink.Variant 对象,从而允许您将多个选项作为一组来切换激活。您可以在仿真之前在 MATLAB 环境中或在编译生成的代码时,通过更改 VSSMODE
的值来切换一组变体,如下一节所述。在此示例中,LeftController 和 RightController 引用相同的变体对象,以便您可以同时切换它们。
非线性控制器子系统实现滞后,而线性控制器子系统充当简单的低通滤波器。打开左侧通道的子系统。右侧通道的子系统与之相似。
生成的代码作为用户定义的宏访问变体控制项变量 VSSMODE
。在此示例中,variants_importedmacros.h
提供 VSSMODE
。在 MATLAB 环境中,您是使用 Simulink.Parameter
对象指定 VSSMODE
。当生成包括预处理器条件句的代码时,它的值将被忽略。但是,该值会用于仿真。传统头文件指定在编译生成的代码时要使用的宏的值,该值最终用于激活嵌入式可执行文件中两个指定的变体之一。
可采用下列存储类之一将变体控制项变量定义为 Simulink.Parameter
对象:
指定了头文件的
Define
或ImportedDefine
CompilerFlag
SystemConstant (AUTOSAR)
在指定的头文件中将数据定义为宏的用户自定义存储类
VSSMODE = Simulink.Parameter; VSSMODE.Value = 1; VSSMODE.DataType = 'int32'; VSSMODE.CoderInfo.StorageClass = 'Custom'; VSSMODE.CoderInfo.CustomStorageClass = 'ImportedDefine'; VSSMODE.CoderInfo.CustomAttributes.HeaderFile = 'variants_importedmacros.h';
使用不同变体对模型进行仿真
由于您将 VSSMODE
的值设置为 1,模型在仿真期间使用非线性控制器。
sim('PreprocessorConditionalsUsingVariantSubsystem')
youtnl = yout;
如果将 VSSMODE
的值更改为 0,则模型在仿真期间使用线性控制器。
VSSMODE.Value = int32(0);
sim('PreprocessorConditionalsUsingVariantSubsystem')
youtl = yout;
您可以绘制和比较线性与非线性控制器的响应:
figure('Tag','CloseMe'); plot(tout, youtnl.signals(1).values, 'r-', tout, youtl.signals(1).values, 'b-') title('Response of Left Channel Linear and Nonlinear Controllers'); ylabel('Response'); xlabel('Time (seconds)'); legend('nonlinear','linear') axis([0 100 -0.8 0.8]);
使用 C 预处理器条件句
此示例模型已配置为生成 C 预处理器条件句。要为模型生成代码,请在工具条的 C 代码选项卡中选择编译。
要激活预处理器条件句的代码生成,请检查是否符合以下条件:
在“配置参数”对话框中的代码生成 > 系统目标文件中选择 Embedded Coder® 目标
在 Variant Subsystem 模块参数对话框中,将变体激活时间参数设置为
code compile
。
在此示例中,生成的代码包括对 Simulink.Variant 对象 LINEAR
和 NONLINEAR
的引用,以及对应于那些变体的宏的定义。这些定义依赖于 VSSMODE
的值,该值在外部头文件 variants_importedmacros.h
中提供。通过对宏 (#define) LINEAR
和 NONLINEAR
使用预处理器条件句 (#if) 可确定激活变体。
在生成的 PreprocessorConditionalsUsingVariantSubsystem_types.h
头文件中定义宏 LINEAR
和 NONLINEAR
:
#ifndef LINEAR #define LINEAR (VSSMODE == 0) #endif
#ifndef NONLINEAR #define NONLINEAR (VSSMODE == 1) #endif
在生成的代码中,与变体相关的代码带有 C 预处理器条件句。例如,在 PreprocessorConditionalsUsingVariantSubsystem.c
中,会根据条件来编译对每个变体的单步函数和初始化函数的调用:
/* Outputs for atomic SubSystem: '<Root>/LeftController' */ #if LINEAR /* Output and update for atomic system: '<S1>/Linear' */ #elif NONLINEAR /* Output and update for atomic system: '<S1>/Nonlinear' */ #endif
关闭示例中的模型、图和工作区变量。
bdclose('PreprocessorConditionalsUsingVariantSubsystem') close(findobj(0,'Tag','CloseMe')); clear LINEAR NONLINEAR VSSMODE clear tout yout youtl youtnl