我是靠谱客的博主 酷炫汽车,最近开发中收集的这篇文章主要介绍生成乱序数组 代码_Simulink模型生成代码详解(2),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本文摘要:

这篇文章主要介绍信号对象(Simulink.Signal和Simulink.Parameter)的不同属性对代码生成的影响。

一 Simulink.Signal

根据上一篇文章的介绍,如果我们想要控制模型中,信号线上信号名的代码生成,可以在信号线上设置信号名,并关联到Simulink.Signal的对象。

定义一个Simulink.Signal的对象的方法很简单,首先要确定这个信号的名称,比如我们要定义一阶滤波器的输入信号x,那我们只要在matlab的命令窗口输入:

x = Simulink.Signal

然后就可以看到,Matlab帮我们定义了一个名叫x的Simulink.Signal对象,除了名字是我们指定的,其他都是属性都是默认的。

51f31c043dab3da56b58d021e84f3c12.png

对于代码生成,我们首先要根据该信号的实际情况,定义该信号的数据类型(必须),维度(强烈推荐指定,默认值-1表示维度根据模型实际情况默认推导),初始值(非0的初始值必须指定,个人也推荐指定初始值),采样时间(-1表示默认为根据模型设置的步长相等,这边除了模型的输入信号推荐指定采样时间外,模型内部的变量可以设为-1),最大最小值(模型大的输入和输出信号推荐根据实际情况指定,内部变量如无特殊需要可以不指定),信号意义描述(可选),信号单位(可选),维度模式(这里强烈推荐都设为Fixed),复数的设置(这里强烈推荐都设为real)

所以一个Simulink.Signal对象除了基本信息完整的定义如下:

bb9be535cb0a191e9cbc766ed879fe8e.png

接下来就是本讲的重点,CoderInfo的设置。

默认的CoderInfo被设置为’Auto’,这代码代码生成的形式完全按照系统默认的形式生成:

a4a88eba9d83a327a9af67bdc171e69b.png

我们在matlab的工作空间(workspace)双击x,打开设置界面,然后在Storage class的下拉菜单中,可以看到Simulink.Signal可以选择的Storageclass,选择不同的Storage class,生成代码的形式也会不一样,接下来重点说一下常用的几种Storage class

59d92fccad4ddebc265dd0ea0fac8581.png

1.1 ExportGlobal

该类型表示在生成的代码中会有该变量的声明以及定义。通常应用的场景是这个变量就是在这个模型中算出的,所以需要完整的声明和定义,这是最常用的一种store class。选择ExportGlobal后,会出来两种属性,一个是Alias,这个表示我们可以让这个变量在代码中以Alias中定义的别名声明和定义。Aligment这个属性就保持-1,不用去改了。

3eee94ee5ba146031e6bbd70c52d9f23.png

具体定义的语句为,其他几种Storage class也是用类似的语句去定义,后面就不再描述了。

75993ddde8e9cdc884bfac41feab2e7f.png

接下来我们看一下实际生成的代码,在对应的.h文件中有声明,.c文件中有定义,并且使用的时候就是我们定义的名称x。

d1be6615527cf98aad2b71b93fcfb72e.png

1c503b5e57e75cd50328996a6b681479.png

80e0c231deb6c87d0dd695fd8bcc4d93.png

如果我们设置Alias为xxxxx

9677d53d06208d9f0d95fd201d011f1b.png

再看一下生成的代码,所有地方都变成了我们定义的Alias的名称

88e846435863d2b7a91bc3f5cf99d405.png

a3ca176a2ee35a880340d34a9ec7d282.png

085b33023a5597d09c9f94e6a492dedc.png

1.2 ImportExtern

选择ImportExtern后,出来的属性和ExportGlobal的一样,具体含义也一样。

f5bfaef0a63f30f87807c30d09921d7e.png

ImportExtern和ExportGlobal的区别是,ImportExtern不会生成该变量的定义。因为ImportExtern表示该变量在别的地方已经定义过了,这边只是使用,所以只会生成该变量的声明,以及使用的时候直接使用该变量。但设置为ImportExtern会有个问题,我们无法指定定义这个变量的头文件,所以一般不推荐设置为ImportExtern,更推荐使用ImportFromFile,后面会具体介绍。

6c970891e5f99f0636276fb9ffe6d551.png

1.3 ImportExternPointer

ImportExternPointer和ImportExtern一样,唯一的区别是,使用该变量的时候是用指针的形式

2ce9a0a1b23984707273d624ca1fe421.png

这个的使用场景就是有使用指针需要的情况下使用。

85ff5603fd8cbfb400069ce507375e2d.png

d812498ef9291cad4efc9dc26d158290.png

1.4 ExportToFile

ExportToFile表示该变量的声明和定义可以指定生成到我们规定的文件中。其中变量的声明生成在HeadFile的属性定义的文件中,变量的定义生成在DefinitionFile的属性定义的文件中“Preserve array dimensions”这个属性表示对于多维数组,是否保持维度为多维,或者是将多维数组展开成为一维数组Owner这个属性是在使用model reference生成代码的时候使用的,需要配合模型的设置“Use owner from data object for data definition placement”一起使用,这里就先不讨论了。

58c12eeddaa91280969ddd76d47de5fc.png

生成的代码如下,可以看到,额外多生成了两个文件,分别声明和定义了变量x。

5345fdd1557493c2ed8032ac0a050f07.png

我们将x的维度改为[2,2],不勾选“Preserve array dimensions”,则生成的代码如下,可以看到,会将2x2的数组展开成了1x4的一维数组

b34a86d9438c281691a3eef6527cb259.png

如果勾选了“Preserve array dimensions”,则同时需要在模型设置 arrary layout为 Row-major

34f867070d19aa15c6bc0a23c21baa98.png

生成的代码如下:

eeacd5e9f97c8c5955ef4365cea0305f.png

1.5 ImportFromFile

ImportFromFile表示该变量的声明和定义都是在别的文件中,这个模型只是使用这个变量。具体的属性如下,其中HeadFile定义了该变量声明的头文件,“Preserve array dimensions”这个属性的意义和上面描述的一样。

e095491899974342a098dd3db54b5cc9.png

具体生成的代码如下,会在该模型生成的头文件中包含我们指定的头文件,使用的时候直接使用该变量,不会再生成该变量的声明和定义。

dd282ae31701f740faa8d86353dc92eb.png

1.6 Struct

Struct表示,这个变量是结构体中的一员,具体的属性如下,其中StructName中可以指定结构体的名称,Alias的作用和之前描述的一样,可以给该变量起一个别名。

ffa6669956c2808fc1ed8ad95aecbb00.png

生成的代码如下,在头文件中会定义一个结构体,c文件中使用该结构体,使用的时候直接就是结构体的形式。

0951d1a75c9888d4ffaf51a7ee950a2a.png

dacf18574352b01a7c967c4b2b13c21c.png

1919d1b64f85f130955a59cf1c1a0b82.png

1.7 GetSet

GetSet表示,如果读取该变量的时候,用指定的函数替代,如果对该变量赋值的时候,也是用指定的函数替代。这个在实际项目中很有用,因为一般规范的接口都是使用函数来对接口变量进行读取或者赋值的。GetSet具体的属性如下,HeadFile的属性定义一个头文件名,该头文件中会有接口函数的声明。GetFunction定义读取该变量的函数名,GetFunction定义对该变量赋值的函数名,其中$N是指代该变量的名称。Alias同样可以定义一个该变量的别名。

5a45a2db5c5d01be940c9e6ca055d029.png

这次对x和y做同样的这个设置,具体生成的代码如下,同样会自动包含我们定义的头文件,然后不会再生成x和y的声明和定义,因为这个应该在我们给定的头文件中被声明。在读取x的值的时候,以及为y赋值的时候,都使用了所定义的函数。

837bdd5e5d24637f478d060103a20afa.png

42f2468a5295c87172e5bf6e20666385.png

二 Simulink.Parameter

定义一个Simulink.Parameter的对象的方法和定义Simulink.Signal的方法一样,比如我们要定义一个名叫FilterOffset的参数,那我们只要在matlab的命令窗口输入:

FilterOffset = Simulink.Parameter

然后就可以看到,Matlab帮我们定义了一个名叫FilterOffset的Simulink.Parameter对象,除了名字是我们指定的,其他都是属性都是默认的。

079df0933cd438a37838949971e482eb.png

这里Simulink.Parameter与Simulink.Signal不一样的地方在于,Simulink.Parameter对象有一个Value的属性,这个值是一定要指定的,由于该变量具体的值是指定的,所以对于Simulink.Parameter对象,维度(Dimensions)这个属性就不需要我们指定了,系统会根据我们实际给定的值的维度来自动填写。如果参数是维度是为1的标量,Value就直接写数值就可以了。如果是1维数组,那可以写成如下的形式,数组的值可以用空格或者逗号隔开

b8d6fe91a2ba69c3c696574ef79961d5.png

如果参数是二维数组,那就可以写成如下的形式,不同行的元素之间用分号(;)隔开,同行不同列之间的元素用空格或者逗号隔开

ced445c8d1bf33edec04fd07b5a554c8.png

接下来就是重点,CoderInfo的设置。

我们在matlab的工作空间双击FilterOffset,打开设置界面,然后在Storage class的下拉菜单中,可以看到Simulink.Parameter的对象可以选择的Stoage class。相比Simulink.Signal,多了Const,ConstVolatile,Define和CompilerFlag这四个类型,接下来我们就详细介绍一下这四个类型。其他在Simulink.Signal中也有的Stoage class的类型,其具体生成代码的区别是一样的,这里就不具体再展开说了。

0928da42a4004103c55007339629e258.png

2.1 Const

该类型表示在定义这个参数是一个常量,在该参数声明和定义的时候,都会加上const的修饰符。其具体含有的属性如下,这里的HeadFile和DefinitionFile属性分别可以指定这个参数声明的文件和定义的文件。其中这两个属性都可以缺省为空,如果为空的话,这个参数的声明和定义就会在与模型名同名的.h和.c文件中生成。“Preserve array dimensions”和"Owner"这两个个属性的意义和上一篇文章描述的一样。

c7c1d031fe77a3ed0d11ca4167360a57.png

按照上图的定义,生成的代码如下,该参数的定义和声明都在模型同名的代码文件中,其中const修饰符的作用是,表示该参数是一个常量,代码中不允许再对该参数进行重新赋值,否则的话编译时会报错。

6356f91c25c352a245545ae84c3fa639.png

如果我们指定参数声明和定义的文件,通常这样做的目的是让模型的控制逻辑代码与参数定义代码分开,方便参数的管理

af304ca30a0331a3596e2d02ce1038c3.png

那么生成的代码如下,可以看到,多生成了两个我们指定的文件,里面包含该参数的声明和定义。

a12cb30c495296f58100c3348aa3f2dd.png

2.2 ConstVolatile

表示在定义和声明该变量时,同时会使用 const 和 volatile 两个修饰符。当使用 volatile 声明的变量的时候,系统总是重新从它所在的内存读取数据,以保证读取数据的准确性,因为如果优化过,从寄存器中读取数据的话,寄存器内的数据有可能被意外修改,从而读取到非预期的数据。

在实际的应用代码中,一般都会在定义参数时加上 const 和 volatile 这两个修饰符,以保证参数不会被修改,并且读取值的准确性。

ConstVolatile 中的属性和作用与 Const 的完全一样。

8c919b2e0950a9744795818d25daf470.png

唯一的区别就是在变量声明和定义的时候,会额外加上 volatile 这个修饰符

84bd15b5ce6222061fd1b5bd6951b990.png

2.3 Define

该类型的作用是,把参数直接定义为一个宏。Define所含的属性只有 HeadFile,该属性可以缺省,如果缺省的话,定义该参数的宏会生成在与模型同名的头文件中。如果指定,则定义该参数的宏会生成在指定的头文件中

c0551ab692a6aa47ffc185eb1ed64034.png

HeadFile缺省的情况下生成的代码如下:

69f17ef47dfecd2f1088262f470ad676.png

对于一些公用的,值不变的常量,可以指定头文件,这样该变量就不会出现在该模型名对应的代码文件中,生成的代码只会包含指定的头文件。

30733de0a0a3a62dda24f2e7b5a00b70.png

36f612de447760dac0eb4aace850ad70.png

值得注意的是,参数的值只有是标量的时候,才能设置为Define,对于数组,不可以设为该类型,否则生成代码会报错。比如查表模块中的参数,就不能设为Define。

23e382df28fbdbc6ef8f63c9be75ea59.png

2.4 CompilerFlag

该类型与Define类似,这个类型主要应用在,通过参数来控制编译不同的代码。比如有一个可变子系统,里面有两个子系统,我们想通过一个参数来控制编译哪个子系统。

a48fcb3305cbbce10f04148d1babdca6.png

这时我们就可以把控制条件中的参数FilterMode设为CompilerFlag

ea9923ae3c1372c77a9c8e0cf7ed7496.png

该类型不再包含具体的属性了,生成代码时不会生成其定义,而是直接使用。该变量的宏定义应该在与编译相关的文件中被定义

4a9b81132c509221d5772bec1c8fcc2c.png

这样,所有Simulink.Parameter中常用的storeclass就介绍完了,实际使用时,可以根据对生成代码形式的需求,来选择对应的store class。

最后

以上就是酷炫汽车为你收集整理的生成乱序数组 代码_Simulink模型生成代码详解(2)的全部内容,希望文章能够帮你解决生成乱序数组 代码_Simulink模型生成代码详解(2)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部