Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

在生成的代码中创建可调标定参数

标定参数是存储在全局内存中的一个值,供算法读取用于计算但不写入。标定参数是可调的,因为您可以在执行算法的过程中更改存储的值。创建标定参数可以:

  • 通过在执行过程中调整参数和监控信号值,确定最佳参数值。

  • 通过覆盖内存中存储的参数值,有效地调整算法以适应不同的执行条件。例如,通过在每个车辆的引擎控制单元存储不同的参数值,可对不同质量的多个车辆使用同一个控制算法。

在 Simulink® 中,可以创建一个 Simulink.Parameter 对象来表示标定参数。您可以使用参数对象来设置模块参数值,例如 Gain 模块的增益参数。要控制参数对象在生成的代码中的表示,请对该对象应用存储类。

要使模块参数在生成的代码中默认可访问(例如为了建立快速原型),请将默认参数行为(请参阅默认参数行为)设置为可调。有关详细信息,请参阅Preserve Variables in Generated Code

将模块参数表示为可调全局变量

此示例说明如何在生成的代码中通过将模块参数表示为全局变量来创建可调参数数据。

使用参数对象配置模块参数

打开示例模型 InlineBlockParameters 并将其配置为显示生成的模块名称。

load_system('InlineBlockParameters')
set_param('InlineBlockParameters','HideAutomaticNames','off')
open_system('InlineBlockParameters')

建模选项卡上,点击模型数据编辑器

在模型数据编辑器中,检查参数选项卡。

在模型中,点击 Gain 模块 G1。模型数据编辑器突出显示与模块的增益参数对应的行。

在模型数据编辑器的列,将增益值从 2 更改为 myGainParam

myGainParam 旁边,点击操作按钮(含三个纵点),然后选择创建

在“创建新数据”模块对话框中,将设置为 Simulink.Parameter(2)。点击创建Simulink.Parameter 对象 myGainParam 在模型工作区中存储参数值 2

在 myGainParam 对话框的代码生成选项卡上,点击在 Coder App 中配置

在代码映射编辑器中,将 myGainParam存储类设置为 ExportedGlobal。此存储类使参数对象在生成的代码中显示为可调全局变量。

或者,要创建参数对象并配置模型,请在命令提示符下使用以下命令:

set_param('InlineBlockParameters/G1','Gain','myGainParam')
mws = get_param('InlineBlockParameters', 'modelworkspace');
mws.assignin('myGainParam',Simulink.Parameter(2));
cm = coder.mapping.utils.create('InlineBlockParameters');
setModelParameter(cm,'myGainParam','StorageClass','ExportedGlobal');

使用模型数据编辑器为 Gain 模块 G2 创建参数对象 myOtherGain。应用存储类 ExportedGlobal

也可以在命令提示符下使用以下命令:

set_param('InlineBlockParameters/G2','Gain','myOtherGain')
mws.assignin('myOtherGain',Simulink.Parameter(-2));
setModelParameter(cm,'myOtherGain','StorageClass','ExportedGlobal');

生成和检查代码

从模型中生成代码。

slbuild('InlineBlockParameters')
### Starting build procedure for: InlineBlockParameters
### Successful completion of build procedure for: InlineBlockParameters

Build Summary

Top model targets built:

Model                  Action                        Rebuild Reason                                    
=======================================================================================================
InlineBlockParameters  Code generated and compiled.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 31.743s

生成的文件 InlineBlockParameters.h 包含全局变量 myGainParammyOtherGainextern 声明。您可以包含 (#include) 此头文件,以使您的代码能够在执行过程中读写变量的值。

file = fullfile('InlineBlockParameters_grt_rtw','InlineBlockParameters.h');
coder.example.extractLines(file,...
    'extern real_T myGainParam;','Referenced by: ''<Root>/G2''',1,1)
extern real_T myGainParam;             /* Variable: myGainParam
                                        * Referenced by: '<Root>/G1'
                                        */
extern real_T myOtherGain;             /* Variable: myOtherGain
                                        * Referenced by: '<Root>/G2'

文件 InlineBlockParameters.cmyGainParammyOtherGain 分配内存并进行初始化。

file = fullfile('InlineBlockParameters_grt_rtw','InlineBlockParameters.c');
coder.example.extractLines(file,...
    '/* Exported block parameters */','Referenced by: ''<Root>/G2''',1,1)
/* Exported block parameters */
real_T myGainParam = 2.0;              /* Variable: myGainParam
                                        * Referenced by: '<Root>/G1'
                                        */
real_T myOtherGain = -2.0;             /* Variable: myOtherGain
                                        * Referenced by: '<Root>/G2'

模型 step 函数中生成的代码算法使用 myGainParammyOtherGain 进行计算。

coder.example.extractLines(file,...
    '/* Model step function */','/* Model initialize function */',1,0)
/* Model step function */
void InlineBlockParameters_step(void)
{
  /* Outport: '<Root>/Out1' incorporates:
   *  Gain: '<Root>/G1'
   *  Gain: '<Root>/G2'
   *  Inport: '<Root>/In1'
   *  Sum: '<Root>/Sum'
   */
  InlineBlockParameters_Y.Out1 = myGainParam * InlineBlockParameters_U.In1 +
    myOtherGain * -75.0;
}

当模块参数引用 MATLAB 数值变量时应用存储类

如果使用数值变量来设置模块参数的值,则不能将存储类应用于该变量。作为解决方法,您可以将该变量转换为参数对象,然后对该对象应用一个存储类。要将变量转换为参数对象,请选择下列方法之一:

  • 在模型数据编辑器的参数选项卡上,将更改视图设置为代码,找到与该变量对应的行。在存储类列中,从下拉列表中选择转换为参数对象。模型数据编辑器会将变量转换为参数对象。然后,使用存储类列将存储类应用于该对象。

    您也可以在模型资源管理器中使用这种方法。

  • 使用数据对象向导(请参阅使用数据对象向导为模型创建数据对象)。在该向导中,选中参数复选框。该向导将变量转换为对象。然后,使用模型数据编辑器或模型资源管理器对这些对象应用存储类。

创建表示标定参数的存储类 (Embedded Coder)

以下示例说明如何创建在生成的代码中生成标定参数的存储类。存储类使每个参数对象 (Simulink.Parameter) 显示为具有特殊装饰(例如关键字和 pragma 指令)的全局变量。

在生成的代码中,标定参数必须显示为在文件 calPrms.c 中定义并在 calPrms.h 中声明的全局变量。变量定义必须如下所示:

#pragma SEC(CALPRM)

const volatile float param1 = 3.0F;
const volatile float param2 = 5.0F;
const volatile float param3 = 7.0F;

#pragma SEC()

这些变量使用关键字 constvolatile。pragma 指令 #pragma SEC(CALPRM) 控制变量在内存中的位置。要实现这一 pragma 指令,变量定义必须出现在相邻的代码块中。

此外,生成的代码必须包含每个参数的 ASAP2 (a2l) 描述。

创建用于存储存储类和内存段定义的包

在当前文件夹中创建一个包。向该包中添加一个新存储类和一个关联内存段的定义。然后,将该存储类应用于模型中的数据对象。

  1. 打开包含包 MATLAB® 命名空间文件夹 +myPackage 的示例。该包存储 ParameterSignal 类的定义。

    openExample('ecoder/ExploreExampleModelCustomStorageClassesExample')

  2. 在命名空间文件夹 +myPackage 内导航到文件 Signal.m

  3. 打开 Signal.m,取消对定义方法 setupCoderInfomethods 节的注释。在对函数 useLocalCustomStorageClasses 的调用中,用 'myPackage' 替换 'packageName'

      methods
        function setupCoderInfo(h)
          % Use custom storage classes from this package
          useLocalCustomStorageClasses(h, 'myPackage');
        end
      end % methods

  4. 保存并关闭文件。

  5. 打开文件 Parameter.m,并对文件 Signal.m 进行相同的更改。

  6. 保存并关闭文件。

创建存储类和内存段

  1. 将当前文件夹设置为包含包命名空间文件夹 +myPackage 的文件夹。

  2. 打开自定义存储类设计器。

    cscdesigner('myPackage')
  3. 在自定义存储类设计器中的内存段选项卡上,点击新建

  4. 对于新内存段,将属性设置为下表中列出的值。

    属性
    名称CalMem
    语句围绕变量组
    前置语句#pragma SEC(CALPRM)
    后置语句#pragma SEC()
    是常量选择
    是变量选择

  5. 点击应用

  6. 自定义存储类选项卡上,点击新建

  7. 对于新存储类,将属性设置为下表中列出的值。

    属性
    名称CalParam
    针对信号清除
    数据作用域导出
    头文件calPrms.h
    定义文件calPrms.c
    内存段CalMem

  8. 点击确定。出现询问是否保存更改的消息时,点击

将默认参数对象设置为 myPackage.Parameter

为了更轻松地应用存储类,请使用模型资源管理器将默认参数对象从 Simulink.Parameter 更改为 myPackage.Parameter

  1. 在命令提示符下,打开模型资源管理器。

    daexplr

  2. 在模型资源管理器的模型层次结构窗格中,选择基础工作区

  3. 在模型资源管理器工具栏中,点击添加 Simulink 参数按钮旁边的箭头。在下拉列表中,选择自定义类列表

  4. 自定义类列表对话框的参数类下,选中myPackage.Parameter 旁边的复选框。点击确定

  5. 在模型资源管理器工具栏中,点击添加 Simulink 参数按钮旁边的箭头。在下拉列表中,选择 myPackage 参数

    基础工作区中将显示一个 myPackage.Parameter 对象。您可以删除此对象。

现在,当您使用诸如模型数据编辑器之类的工具创建参数对象时,Simulink 将创建 myPackage.Parameter 对象而不是 Simulink.Parameter 对象。

应用存储类

在示例模型 RollAxisAutopilot 中,BasicRollMode 子系统表示 PID 控制器。将 PID 参数配置为标定参数。

  1. 打开模型。

    openExample('RollAxisAutopilot');

  2. 在模型中,导航到 BasicRollMode 子系统中。

  3. 打开 Embedded Coder。

  4. 在模块图下方,通过选择模型数据编辑器选项卡打开模型数据编辑器。

  5. 在模型数据编辑器中,选择参数选项卡并更新模块图。

    现在,数据表包含与 Gain 模块使用的工作区变量(代表控制器的 P、I 和 D 参数)对应的行。

  6. 在模型数据编辑器中,在过滤内容框的旁边,激活基于所选项进行过滤按钮。

  7. 在模型中,选择三个 Gain 模块。

  8. 过滤内容框中,输入 model workspace

    Gain 模块使用的变量位于模型工作区中。

  9. 在数据表中,选择三个行,并在一行的存储类列中选择转换为参数对象

    模型数据编辑器将工作区变量转换为 myPackage.Parameter 对象。现在,您可以对这些对象应用存储类。

  10. 在一行的存储类列中,选择 CalParam

生成和检查代码

  1. 从模型中生成代码。

  2. 在代码生成报告中,检查文件 calPrms.c。该文件定义标定参数。

    /* Exported data definition */
    #pragma SEC(CALPRM)
    
    /* Definition for custom storage class: CalParam */
    const volatile real32_T dispGain = 0.75F;
    const volatile real32_T intGain = 0.5F;
    const volatile real32_T rateGain = 2.0F;
    
    #pragma SEC()

    文件 calPrms.h 声明参数。

  3. 检查接口文件 RollAxisAutopilot.a2l。该文件包含有关每个参数的信息,例如 dispGain

    /begin CHARACTERISTIC
      /* Name                   */      dispGain  
      /* Long Identifier        */      ""
      /* Type                   */      VALUE 
      /* ECU Address            */      0x0000 /* @ECU_Address@dispGain@ */ 
      /* Record Layout          */      Scalar_FLOAT32_IEEE 
      /* Maximum Difference     */      0 
      /* Conversion Method      */      RollAxisAutopilot_CM_single 
      /* Lower Limit            */      -3.4E+38 
      /* Upper Limit            */      3.4E+38
    /end CHARACTERISTIC

从系统常量或其他宏初始化参数值 (Embedded Coder)

您可以生成使用从某些系统常量(宏)计算的值初始化可调参数的代码。例如,您可以生成以下代码,这些代码使用从宏 numVesselsvesInitVol 计算出的值初始化可调参数 totalVol

#define numVessels 16
#define vesInitVol 18.2

double totalVol = numVessels * vesInitVol;

这种初始化方法会保留可调参数和系统常量之间的数学关系,从而使生成的代码更易读、更易于维护。要生成此代码,请执行下列操作:

  1. 创建表示系统常量的参数对象。

    numVessels = Simulink.Parameter(16);
    vesInitVol = Simulink.Parameter(18.2);

  2. 将这些对象配置为使用存储类 Define,这会在生成的代码中生成一个宏。

    numVessels.CoderInfo.StorageClass = 'Custom';
    numVessels.CoderInfo.CustomStorageClass = 'Define';
    
    vesInitVol.CoderInfo.StorageClass = 'Custom';
    vesInitVol.CoderInfo.CustomStorageClass = 'Define';

  3. 创建另一个表示可调参数的参数对象。将该对象配置为使用存储类 ExportedGlobal,这会在生成的代码中生成一个全局变量。

    totalVol = Simulink.Parameter;
    totalVol.CoderInfo.StorageClass = 'ExportedGlobal';

  4. 使用表达式 numVessels * vesInitVol 设置 totalVol 的值。要指定生成的代码保留表达式,请使用 slexpr 函数。

    totalVol.Value = slexpr('numVessels * vesInitVol');

  5. 使用 totalVol 在模型中设置模块参数值。您从模型生成的代码使用基于系统常量的值来初始化可调参数。

有关使用表达式设置 Simulink.Parameter 对象的值的详细信息和限制,请参阅使用数学表达式设置变量值

存储位置对参数对象的代码生成的影响

您可以在基础工作区、模型工作区或数据字典中创建参数对象。但是,当您结束 MATLAB 会话时,基础工作区中的变量将被删除。要确定模型使用的参数对象和其他变量的存储位置,请参阅确定在何处存储 Simulink 模型的变量和对象

参数对象的位置可能会影响生成的代码中对应数据定义的文件位置。

  • 如果您将一个参数对象放在基础工作区或数据字典中,代码生成器将假定对应的参数数据(例如全局变量)属于您从中生成代码的系统,而不是属于系统中的特定组件。例如,如果模型引用层次结构中的某个模型使用了一个参数对象,而该对象的存储类不是 Auto,则数据定义将显示在为层次结构中的顶层模型生成的代码中,而不是为使用该对象的模型生成的代码中。

    但是,如果您拥有 Embedded Coder®,则可以使用某些存储类指定数据片段所属模型的名称。指定所属模型后,为该模型生成的代码将定义数据。有关数据所属关系的详细信息,请参阅Control Placement of Global Data Definitions and Declarations in Generated Files (Embedded Coder)

  • 如果您将参数对象放在模型工作区中,代码生成器将假定数据属于该模型。如果您从包含所属模型的引用层次结构中生成代码,数据定义将显示在为所属模型生成的代码中。

    有关数据所属关系的详细信息,请参阅Control Placement of Global Data Definitions and Declarations in Generated Files (Embedded Coder)

  • 如果您对参数对象应用除 Auto 以外的存储类,该对象在生成的代码中将显示为全局符号。因此,在模型引用层次结构中,位于不同模型工作区或字典中的两个这样的对象不能具有相同的名称。每个对象的名称在整个模型层次结构中必须唯一。

    但是,如果您有 Embedded Coder,则可以使用存储类 FileScope 来防止不同模型工作区中参数对象之间的名称冲突。请参阅使用 Struct 存储类将参数数据组织为结构体 (Embedded Coder)

如果您将 AUTOSAR.Parameter 对象存储在模型工作区中,代码生成器将忽略您为该对象指定的存储类。

配置信号数据的可访问性

在算法执行过程中调整参数值时,可以监控或捕获输出信号值,以分析调整的结果。要在生成的代码中将信号表示为可访问数据,可以使用测试点和存储类等技术。请参阅Preserve Variables in Generated Code

用于调整参数的编程接口

您可以配置生成的代码以包括:

设置可调参数的最小值和最大值

为可调参数指定最小值和最大值是一种不错的做法。

您可以通过以下方式指定最小值和最大值:

  • 在使用参数对象的模块对话框中。使用这种方式将最小值和最大值信息存储在模型中。

  • 通过使用用来设置参数值的 Simulink.Parameter 对象的属性。使用这种方式将最小值和最大值信息存储在模型外。

有关详细信息,请参阅指定模块参数的最小值和最大值

其他建模目的注意事项

目的注意事项和更多信息
应用存储类型限定符 constvolatile

如果您有 Embedded Coder,要生成存储类型限定符,请参阅Protect Global Data with const and volatile Type Qualifiers (Embedded Coder)

通过应用关键字 static 防止在不同组件中的参数之间发生名称冲突

如果您有 Embedded Coder,请使用存储类 FileScope 或您创建的类似存储类。请参阅Choose Storage Class for Controlling Data Representation in Generated Code (Embedded Coder)

生成 ASAP2 (a2l) 描述

您可以生成一个 a2l 文件,以使用 ASAP2 标准说明您的标定参数。有关详细信息,请参阅导出 ASAP2 文件用于数据测量和标定

生成 AUTOSAR XML (ARXML) 描述

如果您拥有 Embedded Coder,可以生成一个 ARXML 文件,以说明您为 AUTOSAR 标准配置的模型所使用的标定参数。请参阅Model AUTOSAR Calibration Parameters and Lookup Tables (AUTOSAR Blockset)

存储查找表数据进行标定

要存储查找表数据以根据 ASAP2 或 AUTOSAR 标准(例如 STD_AXIS、COM_AXIS 或 CURVE)进行标定,可以在查找表模块中使用 Simulink.LookupTableSimulink.Breakpoint 对象。

但是,这存在一些限制。请参阅 Simulink.LookupTable。要绕过 Simulink.LookupTableSimulink.Breakpoint 对象的限制,可以改用 Simulink.Parameter 对象。

有关详细信息,请参阅为查找表定义 ASAP2 信息Configure Lookup Tables for AUTOSAR Calibration and Measurement (AUTOSAR Blockset)

使用 pragma 指令将参数数据存储在特定的内存位置

如果您拥有 Embedded Coder 许可证,要生成包含自定义 pragma 指令的代码,请使用存储类和内存段。请参阅Control Data and Function Placement in Memory by Inserting Pragmas (Embedded Coder)

另请参阅

| |

相关主题