2. 代码生成配置参数详解

任务定义

本案例面向使用 Embedded Coder 将 Simulink 模型生成嵌入式 C 代码的工程师,目标是系统梳理并解释代码生成过程中最关键的一组配置参数,说明每个参数控制什么行为、可选值如何影响生成代码,并给出一个可实际打开查看的配置入口路径。案例不要求生成完整工程,而是聚焦于“配置项—生成代码特征”的对应关系,使读者能根据目标硬件与代码风格需求,准确找到并设置对应参数。

配置参数总览与作用域

Embedded Coder 的代码生成配置集中在模型配置参数对话框的 Code Generation 面板及其子面板中。所有参数均通过 rtwgensettings 结构或 coder.config 对象进行编程式访问。下表列出核心参数及其影响范围:

参数路径(对话框位置)参数名称(编程接口)关键可选值对生成代码的影响
Code Generation > GeneralSystemTargetFileert.tlc / grt.tlc选择 ERT 目标生成嵌入式可移植代码;GRT 用于桌面仿真
Code Generation > GeneralGenerateCodeOnlyon/off仅生成代码不启动构建流程
Code Generation > LanguageTargetLangC / C++指定输出语言
Code Generation > Code StyleParenthesesLevelNominal/Minimum/Maximum控制表达式中括号数量,影响可读性与编译器优化
Code Generation > Code StylePreserveExpressionOrderon/off保持表达式求值顺序,避免编译器重排
Code Generation > InterfaceGenerateReporton/off生成代码生成报告(HTML)
Code Generation > InterfaceGenCodeOnlyThirdPartyon/off仅生成代码供第三方工具链编译
Code Generation > Interface > Data ExchangeMatFileLoggingon/offERT 下关闭可移除 MAT 文件记录代码
Code Generation > Interface > Data ExchangeSupportContinuousTimeon/off关闭可移除连续时间支持代码
Code Generation > Interface > Data ExchangeSupportNonFiniteon/off关闭可移除 NaN/Inf 检查分支
Code Generation > Interface > Data ExchangeSupportComplexon/off关闭可移除复数运算支持
Code Generation > Interface > Data ExchangeSupportAbsoluteTimeon/off关闭可移除时间戳代码
Code Generation > OptimizationOptimizationCustomizeon/off启用自定义优化选项
Code Generation > OptimizationDefaultParameterTuningon/off允许调参(生成参数结构体)
Code Generation > OptimizationOptimizeBlockIOStorageon/off复用块间信号内存,减少 RAM
Code Generation > OptimizationOptimizeDataStoreon/off优化 Data Store 内存复用
Code Generation > Optimization > SignalsBufferReuseon/off信号缓冲区复用
Code Generation > Optimization > SignalsLocalBlockOutputson/off块输出使用局部变量而非全局缓冲区
Code Generation > Optimization > SignalsReuseLocalBlockOutputson/off局部输出变量复用
Code Generation > Optimization > SignalsReuseLocalBlockOutputsThreshold数值局部复用阈值
Code Generation > Optimization > BlocksInlineInvariantSignalson/off将常量信号内联为立即数
Code Generation > Optimization > BlocksInlineParameteron/off将模型参数(工作区变量)内联为宏或常量
Code Generation > Optimization > BlocksLocalBlockOutputson/off块输出局部化
Code Generation > Optimization > BlocksRollThreshold数值向量运算展开为循环的阈值
Code Generation > Optimization > BlocksStrengthReductionon/off强度削减优化(乘除转移位等)
Code Generation > Optimization > BlocksDeadCodeEliminationon/off死代码消除
Code Generation > Optimization > BlocksExpressionFoldingon/off表达式折叠,减少临时变量
Code Generation > Optimization > BlocksFoldNonScalaron/off非标量表达式折叠
Code Generation > Optimization > BlocksConditionalInputBranchOptimizationon/off条件输入分支优化
Code Generation > Optimization > BlocksUseFloatMulNetSlopeon/off使用浮点乘法计算网络斜率
Code Generation > Optimization > BlocksUseSpecifiedMinMaxon/off使用信号范围信息优化
Code Generation > Optimization > GlobalEfficientFloat2IntCaston/off高效浮点转整型实现
Code Generation > Optimization > GlobalEfficientMapNaN2Inton/offNaN 映射到整型的优化
Code Generation > Optimization > GlobalUseCustomFixedPointTypeson/off使用自定义定点类型
Code Generation > Optimization > GlobalCustomFixedPointType类型名自定义定点类型名称
Code Generation > Optimization > GlobalUseCustomMemoryManageron/off使用自定义内存管理函数
Code Generation > Optimization > GlobalCustomMemoryManager函数名自定义内存分配/释放函数

关键参数行为详解

SystemTargetFile(ert.tlc) 是嵌入式代码生成的基础,选择 ERT 目标后,代码生成器会省略 GRT 中的仿真支持代码,生成更精简的、面向生产的 C 代码。GenerateCodeOnly 置 on 时,只生成 .c/.h 文件而不调用编译器,适合先检查代码再手动集成到外部工程。

InlineParameter 是影响代码中常量表达方式的核心开关。当置 on 且模型工作区变量设置为 Parameter 类型时,生成代码中该参数会以宏定义(#define)形式出现;置 off 时则生成全局结构体变量,便于运行时调参。与之配合的 DefaultParameterTuning 若置 on,则强制生成参数结构体,即使 InlineParameter 为 on 也会被覆盖。

LocalBlockOutputs 与 BufferReuse 共同决定块间信号的内存分配策略。LocalBlockOutputs 置 on 时,每个块的输出优先使用函数内局部变量,减少全局缓冲区数量;BufferReuse 置 on 时,不同块可复用同一段内存(当生命周期不重叠时)。两者同时开启可显著降低 RAM 占用,但会降低代码可读性,因为中间变量名变为 rtb_xxx 形式。

ExpressionFolding 控制是否将多个块的计算表达式合并为一个复杂表达式,减少临时变量和语句数量。置 on 时生成代码更紧凑,但单行表达式可能很长,不利于单步调试。若需要逐块设置断点观察中间值,应将其关闭。

ParenthesesLevel 设为 Maximum 时,生成代码中所有运算均加括号,完全明确优先级,可读性好但代码冗长;设为 Minimum 时依赖 C 语言默认优先级,代码更紧凑。对于安全关键应用建议 Maximum。

SupportNonFinite、SupportComplex、SupportAbsoluteTime、SupportContinuousTime 四个开关用于裁剪不需要的运行时支持代码。若模型只处理有限浮点数、无复数、无时间、无连续状态,全部关闭可移除大量条件分支和辅助函数,减小代码体积。

配置参数编程式访问示例

以下 MATLAB 脚本演示如何通过编程方式读取和修改上述关键配置参数,适用于需要批量配置多个模型或自动化构建的场景:

% 加载模型(需先打开或存在)
model = 'myModel';
load_system(model);

% 获取配置对象
cs = getActiveConfigSet(model);
rtwgen = get_param(cs, 'RTWGen');

% 读取当前值
target = get_param(rtwgen, 'SystemTargetFile');
fprintf('当前目标: %s\n', target);

% 设置关键参数
set_param(rtwgen, 'SystemTargetFile', 'ert.tlc');
set_param(rtwgen, 'GenerateCodeOnly', 'on');
set_param(rtwgen, 'TargetLang', 'C');
set_param(rtwgen, 'InlineParameter', 'on');
set_param(rtwgen, 'LocalBlockOutputs', 'on');
set_param(rtwgen, 'BufferReuse', 'on');
set_param(rtwgen, 'ExpressionFolding', 'on');
set_param(rtwgen, 'ParenthesesLevel', 'Minimum');
set_param(rtwgen, 'SupportNonFinite', 'off');
set_param(rtwgen, 'SupportComplex', 'off');
set_param(rtwgen, 'SupportAbsoluteTime', 'off');
set_param(rtwgen, 'SupportContinuousTime', 'off');

% 应用配置到模型
set_param(cs, 'RTWGen', rtwgen);

% 保存模型(可选)
% save_system(model);

% 生成代码(GenerateCodeOnly=on 时仅生成不编译)
evalin('base', ['rtwbuild(''' model ''')']);

配置参数与生成代码特征对照

为直观展示参数效果,以一个包含增益、求和、饱和的简单模型为例,说明不同配置下生成代码的差异。模型输入为 u,输出为 y,增益系数为工作区变量 K。

% 模型构建脚本(用于生成测试模型)
% 在 MATLAB 中运行以下命令创建模型
new_system('param_demo');
add_block('simulink/Sources/In1', 'param_demo/In1');
add_block('simulink/Math Operations/Gain', 'param_demo/Gain');
add_block('simulink/Math Operations/Sum', 'param_demo/Sum');
add_block('simulink/Discontinuities/Saturation', 'param_demo/Sat');
add_block('simulink/Sinks/Out1', 'param_demo/Out1');
set_param('param_demo/Gain', 'Gain', 'K');
set_param('param_demo/Sum', 'Inputs', '++');
set_param('param_demo/Sat', 'UpperLimit', '10');
set_param('param_demo/Sat', 'LowerLimit', '-10');
add_line('param_demo', 'In1/1', 'Gain/1');
add_line('param_demo', 'Gain/1', 'Sum/1');
add_line('param_demo', 'In1/1', 'Sum/2');
add_line('param_demo', 'Sum/1', 'Sat/1');
add_line('param_demo', 'Sat/1', 'Out1/1');
K = 2.5;  % 定义工作区参数
save_system('param_demo');

配置 A(默认风格):InlineParameter=off,LocalBlockOutputs=off,ExpressionFolding=off。生成代码特征:参数 K 出现在全局参数结构体 param_demo_P.K 中,每个块的输出均有独立全局变量 param_demo_B.Gain、param_demo_B.Sum,语句逐块展开。

/* 配置A预期代码结构(示意) */
/* 参数结构体 */
typedef struct {
  real_T K;  /* 增益 */
} P_param_demo_T;
static P_param_demo_T param_demo_P;

/* 块信号结构体 */
typedef struct {
  real_T Gain;  /* 增益输出 */
  real_T Sum;   /* 求和输出 */
} B_param_demo_T;
static B_param_demo_T param_demo_B;

/* 步进函数 */
void param_demo_step(void)
{
  param_demo_B.Gain = param_demo_P.K * param_demo_U.In1;
  param_demo_B.Sum = param_demo_B.Gain + param_demo_U.In1;
  param_demo_Y.Out1 = saturate(param_demo_B.Sum, -10.0, 10.0);
}

配置 B(紧凑优化):InlineParameter=on,LocalBlockOutputs=on,ExpressionFolding=on,BufferReuse=on。生成代码特征:K 内联为宏 #define K (2.5),中间结果使用局部变量,表达式折叠为单条赋值语句。

/* 配置B预期代码结构(示意) */
#define K (2.5)  /* 内联参数 */

void param_demo_step(void)
{
  real_T rtb_Sat;
  rtb_Sat = saturate(K * param_demo_U.In1 + param_demo_U.In1, -10.0, 10.0);
  param_demo_Y.Out1 = rtb_Sat;
}
配置参数 → 生成代码特征映射 配置参数组 SystemTargetFile = ert.tlc InlineParameter = on/off LocalBlockOutputs = on/off ExpressionFolding = on/off BufferReuse = on/off ParenthesesLevel = Min/Max SupportNonFinite = off SupportComplex = off SupportAbsoluteTime = off 生成代码特征 配置A(默认) • 参数 → 全局结构体 P.K • 块输出 → 全局缓冲区 B.Gain, B.Sum • 逐块语句,可读性好,RAM占用高 配置B(紧凑) • 参数 → #define K (2.5) 宏内联 • 块输出 → 局部变量 rtb_Sat • 表达式折叠,代码量小,RAM占用低 裁剪类开关效果 • SupportNonFinite=off → 移除 isnan/isinf 检查 • SupportComplex=off → 移除复数结构体与运算 • SupportAbsoluteTime=off → 移除时间戳变量 • SupportContinuousTime=off → 移除连续积分器状态

验证方法与判定标准

验证步骤:

  1. 在 MATLAB 中运行上述模型构建脚本创建 param_demo 模型。
  2. 运行配置脚本,分别设置配置 A 和配置 B 的参数组合。
  3. 执行 rtwbuild('param_demo') 生成代码(GenerateCodeOnly=on 时仅生成不编译)。
  4. 打开生成目录下的 param_demo.c 与 param_demo.h 文件,检查以下特征:

判定标准:

  • 配置 A 下:param_demo_P 结构体包含 K 字段;param_demo_B 结构体包含 Gain 与 Sum 字段;步进函数中三条赋值语句逐块出现。
  • 配置 B 下:文件头部出现 #define K (2.5);步进函数中仅有一个局部变量 rtb_Sat;表达式合并为单条赋值语句。
  • 裁剪类开关全部置 off 后,生成代码中不包含 rtIsNaN、rtIsInf、creal_T、getTime 等符号。
  • 若以上特征与配置对应关系一致,则验证通过。

注意:上述预期代码结构为基于配置逻辑的确定性输出示例,实际生成代码可能因 MATLAB 版本不同在变量命名前缀(如 rtb_、rtU、rtY)上略有差异,但结构特征与配置对应关系不变。