RhinoFreak 发表于 2021-12-5 06:19

Simulink模型生成代码详解(1)

前言:
该系列文章主要详细说明基于Simulink模型,怎样对自动生成代码的形式进行控制,以达到生成自己想要的代码形式的目的。
一个Simulink模型可以生成代码的前提有两点:
1.该模型可以通过仿真
2.该模型的参数设置合适。
我们先拿一个简单的一阶滤波器的模型来做例子。
首先,我们先搭建模型,并且可以通过仿真,并且是你期望的结果,这就满足了第一个条件。接下来就可以把重点放到自动代码生成上面了。模型设置的界面如图1所示,对于自动代码生成来说,最重要的一个设置是将Slove option下的Type改为Fixed-Step,否则生成代码时会报错。



图1. 模型参数设置界面-Solver设置

理论上,这个参数设置好后,就可以由模型自动生成代码了,但由于作者从事的是汽车应用层软件开发,所以还有一个重要的设置需要修改,如图2所示。需要将System target file设为ert.tlc(如果是Autosar架构的自动代码生成的话,则选Autosar.tlc)



图2. 模型参数设置界面-Traget file设置

通过这两个基本设置,就可以由模型自动生成代码了,图3就是在模型原始参数的基础上,只改了上述两个参数设置所生成出来的代码。



图3.未经设置生成的代码

可以看到,虽然代码的逻辑是按照模型的逻辑正确的生成出来了,但是变量名都是结构体的形式,跟正常情况下的变量名不一样,可读性也比较差。那么如何设置可以让Simulink模型生成我们想要的变量名称呢
首先让我们看一下模型


对于信号线上的信号名,如果想要生成的代码不是结构体,而是对应的信号名,有2种方法。
方法1:右键点击信号线,选择Properties



然后在跳出的对话框中,选到Code Generation,然后把Storage class改为ExportedGlobal,这样就会为这个信号名单独生成一个名叫x的全局变量。
类似的,可以将另一个输入信号alpha和输出信号y做同样的设置,这样生成出来的代码如下:


可以看到,信号线上的变量x, alpha和y都被直接定义为了对应的变量,但是查表变量和参数变量都还是结构体,所以实际工作中并不推荐这一种方法,因为这个方法对信号变量的设置只能是默认的一些属性,并且不方便统一管理,以及手动设置比较繁琐,但可以了解一下这种方法,对于不需要统一管理的信号也可以这样手动设置来改善生成代码的可读性。

下面是重点,想要控制信号变量和参数变量的代码生成,我们需要创建变量对象。
Simulink默认的信号对象分两种,一个是Simulink.Signal,另一个是Simulink.Parameter。所有信号线上的变量,以及一些模块内设置的状态变量都属于Simulink.Signal;查表模块的轴和表的参数,参数模块的参数,以及其他模块内定义为参数的属性,都属于Simulink.Parameter。
下图分别是定义了一个Simulink.Signal和一个Simulink.Parameter。对于Simulink.Signal,Datatype这个属性是推荐设置好的,对于Simulink.Parameter,Vaule这个属性是必须的,他定义了该参数的值,Datatype这个属性也是推荐设置好的。这一讲,我们把CoderInfo.StorageClass都定义为'ExportedGlobal',这样这些变量都会被定义,当然如果想要控制代码不同的形式我们还可以改变CoderInfo.StorageClass的设置值,这个在下一讲具体介绍。



定义信号对象得到m脚本

我们把用到的信号变量和参数变量都设置好之后,对于信号变量还要在模型上做如下的设置,右键点击信号线,选择Properties,在弹出的对话框中,勾选Signal name must resolve to Simulink signal object。这表明,alpha这个信号必须和我们之前在m脚本中设置的x的变量对象相关联。这时,如果我们没有定义alpha这个变量对象的话,生成代码的时候将会报错。



关联模型信号和定义的信号对象

设置完这个属性后,信号线上会出现一个类似三叉戟一样的符号,这就表示这个信号线上的信号名关联了信号对象。



我们导入m脚本定义好的所有信号对象,再生成一下模型代码



可以看到这下我们所有设置好的信号变量和参数变量都按照我们预想的名称在代码中呈现了,但好像还有一个结构体变量,这个是怎么回事呢。
原来对于unit delay这类模块,会有一个状态名,他其实是表示一个状态,而我们并没有设置其状态名,于是Simulink又自动给这个状态生成了结构体。如果要消除这个结构体,我们可以自己给这个状态命名,比如这里我们给这个状态命名为filter_state



这里同样有两种方式设置这个状态变量代码生成的形式,一个是直接在这边把Code generation storage class设置为ExportedGlobal



另一种是勾选"State name must resolve to Simulink signal object",然后跟之前第二种方法一样,在m脚本中定义状态变量的信号对象。



这里对于实际项目来说,同样推荐用关联信号对象得到方法,这样方便统一管理。设置完这些之后,再重新生成代码,这次所有的结构体变量都消除了,代码的可读性提高了不少。



下一篇文章将详细介绍信号对象中,不同参数的设置对代码生成的影响。
本篇文章的模型和信号对象定义的m脚本可以从百度网盘下载
链接:https://pan.baidu.com/s/1_U4JzOuJLOLcC4xNrlA5ZQ
提取码:rc29

unityloverz 发表于 2021-12-5 06:28

正要用上,感谢分享[赞同]

kyuskoj 发表于 2021-12-5 06:34

你好,模型转为代码可以,那单独的一个小模块可以转为代码实现嘛?

zifa2003293 发表于 2021-12-5 06:37

你把单独的小模块做成模型就可以了,也可以在模型中单独对某个子系统生成代码的

RedZero9 发表于 2021-12-5 06:38

我的模型属于那种光伏发电最大功率点跟踪模型,光伏板有公式还好理解点,但是电路涉及到了电阻,电感,甚至控制电压源,这些器件,用代码可以实现这些器件连成的电路嘛?

FeastSC 发表于 2021-12-5 06:40

那可能比较适合用simscape进行建模

c0d3n4m 发表于 2021-12-5 06:45

你好,如何在simulink中使用EPWM触发多个ADC通道采集啊?谢谢

KaaPexei 发表于 2021-12-5 06:51

优秀

APSchmidt 发表于 2021-12-5 06:57

作者您好,可否单独出一期文章讲讲这个问题[惊喜]您别的文章质量真的高
页: [1]
查看完整版本: Simulink模型生成代码详解(1)