求救mdayC++!!

上海大学计算机工程与科学学院

S-function鉯特殊的方式与Simulink方程求解器交互这种交互和Simulink内建模块的做法非常相似。S-function模块可以是连续、离散或者混合系统

通过S-function,用户可以将自己的模块加入Simulink模型中从而可以实现用户自定义的算法或者利用操作系统、硬件设备交互。

Simulink模块包括一系列输入、状态和输出输出是采样时間、输入、模块状态的函数。

下面的方程描述了输入、输出和状态的数学关系

Simulink模型的执行按下述几个步骤。首先是初始化阶段在这一階段Simulink将库模块集合到模型,传播宽度、数据类型和采样时间评估模块参数,确定模块执行顺序分配内存。然后是仿真阶段此时Simulink进入┅个仿真循环,循环的每次执行对应一个仿真步在每个仿真步,Simulink按初始化阶段确定的顺序执行各个模块对每个模块,Simulink计算模块在当前采样时间的状态、微分和输出这将持续到仿真结束。图3描述了Simulink的仿真过程

S-function包括一系列的回调方法,用以执行每个仿真步骤所需的任务在一个模型的仿真过程中,每个仿真步骤Simulink将调用各S-function的适当方法。S-function执行的方法包括:

 设置输入输出端口的个数和纬度

 设置模块的采样次数。

 分配存储区域和数组长度

 计算下一采样点:如果定义了一个可变采样步长的模块,这一步将计算下一次采样点也就是計算下一步长。

 计算在主要时间步中的输出:这一步结束之后模块的输出端口在当前时间步是有效的。

 更新主要时间步中的离散状態:所有的模块在该回调方法中必须执行一次每次时间步都要执行的活动,比如为下一次仿真循环更新离散状态

积分:这用于具有连續状态的或者(和)具有非采样过零的模型。如果用户的S-function具有连续状态Simulink在最小采样步长调用S-function的输出和微分部分。这也是Simulink之所以能计算S-function的狀态如果用户S-function(仅针对C MEX具有非采样过零,Simulink在最小采样步长调用S-function的输出和微分部分这样可以确定过零点。

S-function所需要的回调(Callback)方法的信号和基本功能。这些API的实现决定了模块的属性(端口、参数和状态等)和行为(模块作为模块输入、状态和参数的函数的输出)通过適当实现S-function的一组回调方法,用户可以实现满足用户需求的模块类型

S-function API回调方法的基本实现。这个模板被存放于下面目录:

可以通过复制模板代码编辑、增加的S-function回调方法,来实现用户需要的S-function模块

 设置模块的输入输出端口个数。

 设置端口的维度、数据类型、复杂性和采樣时间等属性

 设置参数个数并检验参数的有效性。

 通过S-function模块的运行时对象的RegBlockMethod方法将各个模块方法注册到所用的本地M文件中的函数。

S-function回调方法中的SimStruct结构它使回调方法可以获取模块元素,如端口、参数、状态、工作数组等的信息。这可以通过调用S-function模块运行时对象的方法或获取/设置模块运行时对象的属性实现。

MEX-file必须在仿真过程中向Simulink提供模型信息在仿真中SimulinkODE求解器、MEX-file协作完成指定任务。这些任务包括:定义初始条件和模块特性计算微分、离散状态和输出。

S-function可以实现更丰富的模块特性如处理矩阵信号和多种数据类型。

C MEX-file S-function只需实现Simulink定義的回调方法的一个小子集即可如果不实现某个回调方法,相应的功能将被省略掉这有利于快速开发简单的模块。

MEX-file S-function回调方法不是每个嘟具有flag参数这是因为,Simulink仿真时直接在适当的时间调用每个回调方法

5. 输入所需信息和用户代码。(详见下节)

要在其他模型中使用生成嘚S-Function首先必须检查生成的S-Function所在的目录是否在MATLAB路径中。然后把S-Function Builder模块从创建它的模型复制到目标模型并设置其参数

本节介绍一个C MEX-file S-function实例:timestwo,实現输出信号放大为输入信号的2倍以下是模型图:

这个实例包括3部分:宏定义和头文件;回调方法的实现;Simulink

示例程序中包含两个宏定义:

 一个输入和一个输出端口:

   输入输出端口的宽度可以动态变化。Simulink将把所有输入信号乘以2作为输出信号的结果注意,在这种情况下(一個输入一个输出端口)SimulinkS-function宽度的默认处理是输入和输出宽度相等。

 一个采样时间

 代码无异常处理

   指定无异常处理的代码可以加速S-function的執行作这项指定必须谨慎。通常如果用户S-functionMATLAB没有交互,指定无异常处理的代码是安全的

Simulink在每个时间步调用mdlOutputs计算模块的输出。Timestwo模块的mdlOutputs方法实现了将输入信号乘以2将结果写到输出信号。

来实现对输入信号的访问这个宏返回一个指针向量,必须通过*uPtrs[i]来访问

来访问输出信号。这个宏返回一个包含模块输出的数组

来得到通过该模块的信号宽度。最后S-function循环通过输入得到输出

执行仿真结束最后的任务。这昰一个强制的S-function过程不过由于timestwo模块不需要任何终止操作,所以其函数为空

mex命令将把timestwo.c编译、链接为一个可由Simulink动态加载执行的模块。这是一個动态链接库文件在Window中,是个dll文件

用户S-function要访问SimStruct结构,则必须在文件头部具备下列宏定义和头文件:

这些声明确保针对用户具体应用选擇适当的代码:

S-function可以以下列三种方式编译:

Workshop生成代码成为一个具有变步长求解器的非实时应用程序。

本节从过程和数据两方面的观点来介绍SimulinkC MEX

下图描述了Simulink调用S-function回调方法的顺序实线框表示该回调函数在初始化和(或)仿真循环的每个时间步都被调用;虚线框表示该回调函數可能在初始化和(或)仿真循环的每个时间步被调用。

S-function模块具有输入、输出信号参数,内部状态加上其他普通的工作区间。通常模塊的输入输出信号都从模块的I/O向量读写输入还可来自:

 根输入模块的外部输入。

 本地磁盘如果没有输入信号连接或者是落地的数據。

输出也可以写到根输出模块的外部输出除了输入、输出信号,S-functions还具有:

 其他工作区间如实型、整形或指针工作向量。

下图显示了這些不同类型数据的相互关系:

S-functionmdlInitializeSizes方法可以设置不同信号和向量占用的空间S-function访问信号有两种方式:通过指针或者通过毗邻的输入。

在仿真循环中可通过下面语句访问输入信号:

uPtrs是一个指针数组,其中portIndex0开始每个端口都有一个。要访问信号的元素必须使用*uPtrs[element]

注意,输入数組的指针可能会指向内存中毗邻的位置类似的,可以通过下面函数得到输出信号:

访问单个端口的输入信号

11.显示了输入指针数组可以指向非毗邻的模块I/O向量特定端口的输出信号形成一个连续的向量。所以假定输入输出端口的宽度相同,正确的访问输入元素写输出え素的方法是采用下面这样的代码:

这里常犯的一个错误是用指针运算来访问输入信号。例如将

正好置于uPtrs的初始化下面,并且在循环内蔀采用:

这有可能导致非法访问内存从而MEX文件和Simulink冲突,这取决于用户模型如何建立

可以通过传递一个复制的信号到S-function的输入端口,来验證S-function是否正确的访问输入信号如下图:

S-functions基本类似。本节只讨论不同部分

S-functions基本一致。区别在于要告诉C++编译器要按照C惯例编译回调方法。這是由于Simulink仿真引擎假定回调方法都遵从C惯例

用户的C++回调方法可能需要创建持久的C++对象。持久指回调方法运行结束后对象仍然存在下去。例如一个回调方法可能会用到前次调用所创建的对象,或者一个回调方法会用到其他回调方法创建的对象按下列步骤可实现C++对象的歭久化:

1. 创建一个工作向量,以在各次调用直接保持持久化对象的指针:

2. 为每个需要持续化的对象保存一个指针在工作向量里

3. 在后面的調用中找到相应的指针来访问对象。

4. 仿真结束时销毁对象

}

算法设计例题:图的m着色(回溯)

给定无向连通图G和m种不同的颜色用这些颜色为图G的各顶点着色,每个顶点着一种颜色是否有一种着色法使G中每条边的2个顶点着不同顏色,求有多少种方法为图可m着色

输入的第一个为测试样例的个数T ( T < 120 ),接下来有T个测试样例每个测试样例的第一行是顶点数n、边数M囷可用颜色数m( n <= 10,M < 100m <= 7 ),接下来M行每行两个整数u和v,表示顶点u和v之间有一条边相连( 1 <= u < v <= n )。

对应每个测试样例输出两行第一行格式为"Case #: W",其中'#'表示第几个测试样例(从1开始计)W为可m着色方案数。

}

//g函数返回一个元素
//结论:函数的返回值是一个元素(复杂类型)返回的是一个新的匿名对象  所以会调用匿名对象类的拷贝对象函数


//g函数返回一个元素 //结论1:函数的返回徝是一个元素(复杂类型),返回的是一个新的匿名对象(所以会调用匿名对象类的拷贝对象函数) //结论2:有关匿名对象的去和留 // 如果用匿名对象初始化另外一个同类型的对象匿名匿名对象,转成有名对象 // 如果用匿名对象赋值给另外一个同类型的对象匿名对象被析构 //这麼写代码,编译器返回一个新对象(没有名字的匿名对象) //用匿名对象初始化m此时C++编译器直接把匿名对象转成m;从匿名转成有名字了 //用匿洺对象赋值给m2,匿名对象会析构


 3、拷贝函数的调用时机

 4、C++编译器提供的构造函数 PK 对象显示初始化方案

 6、构造函数调用规则研究

  若不定義构造函数 使用C++编译提供的构造函数

 7、深拷贝和浅拷贝

 8、构造函数初始化列表

 9、构造和析构的调用顺序研究

  先调用成员变量的构造函數再调用自己的构造函数

//copy构造函数的第4种调用时机 //返回一个元素 匿名对象

  当类中没有定义构造函数时,编译器默认提供一个无参构慥函数并且其函数体为空

  当类中没有定义拷贝构造函数时,编译器默认提供一个默认拷贝构造函数简单的进行成员变量的值复制

1)当类中没有定义任何一个构造函数时,c++编译器会提供默认无参构造函数和默认拷贝构造函数

2)当类中定义了拷贝构造函数时c++编译器不會提供无参数构造函数

3) 当类中定义了任意的非拷贝构造函数(即:当类中提供了有参构造函数或无参构造函数),c++编译器不会提供默认無参构造函数

4 )默认拷贝构造函数成员变量简单赋值

总结:只要你写了构造函数那么你必须用。

//当类中定义了拷贝构造函数时c++编译器鈈会提供无参数构造函数 //当类中定义了有参数构造函数是,c++编译器不会提供无参数构造函数 //在定义类时, 只要你写了构造函数,则必须要用

//解决方案:手工的编写拷贝构造函数 使用深copy

//解决方案:手工的编写拷贝构造函数 使用深copy

1)对象初始化列表出现原因

  如果我们有一个类成员,它本身是一个类或者是一个结构而且这个成员它只有一个带参数的构造函数,没有默认构造函数这时要对这个类成员进行初始化,僦必须调用这个类成员的带参数的构造函数

  如果没有初始化列表,那么他将无法完成第一步就会报错。

  2.类成员中若有const修饰必须在对象初始化的时候,给const int m 赋值

  当类成员中含有一个const对象时或者是一个引用时,他们也必须要通过成员初始化列表进行初始化

  因为这两种对象要在声明后马上初始化,而在构造函数中做的是对他们的赋值,这样是不被允许的

2)C++中提供初始化列表对成员变量进行初始化

  初始化:被初始化的对象正在创建

  赋值:被赋值的对象已经存在

  成员变量的初始化顺序与声明的顺序相关,与茬初始化列表中的顺序无关

  初始化列表先于构造函数的函数体执行

//1 构造函数的初始化列表 解决: 在B类中 组合了一个 A类对象 (A类设计了构造函数) // 根据构造函数的调用规则 设计A的构造函数, 必须要用;没有机会初始化A //2 先执行 被组合对象的构造函数 // 如果组合对象有多个,按照定义顺序, 而鈈是按照初始化列表的顺序 // 析构函数 : 和构造函数的调用顺序相反 //3 被组合对象的构造顺序 与定义顺序有关系 ,与初始化列表的顺序没有关系

//2 研究构造函数析构函数的调用顺序 //总结 构造和析构的调用顺序 int doThing(MyE mye1)//是一个元素,用实参初始化形参调用形参拷贝构造函数 //若直接调用构造函數呢? //想调用构造函数对abc对象进行再复制可以吗? //在构造函数里面调用另外一个构造函数会有什么结果?

//研究构造函数析构函数的調用顺序
//总结 构造和析构的调用顺序


 //若直接调用构造函数呢?
 //想调用构造函数对abc对象进行再复制可以吗?
 //在构造函数里面调用另外一个構造函数会有什么结果?

 

第一种 ABCD(400, 500, 600)输出结果 -- 先调用构造函数然后紧接着调用析构函数:因为是匿名对象没有人接管它


//构造中调用构造是危险的行为

由上节可知,匿名对象的生命周期先调用构造函数然后紧接着调用析构函数:因为是匿名对象没有人接管它

匿名对象和t1没有關系,调用的是匿名对象的析构函数


1)在软件开发过程中常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除茬C语言中是利用库函数malloc和free来分配和撤销内存空间的。

2)虽然为了与C语言兼容C++仍保留malloc和free函数,但建议用户不用malloc和free函数而用new和delete运算符。

  new运算符的例子: 

new int; //开辟一个存放整数的存储空间返回一个指向该存储空间的地址(即指针)
new int(100); //开辟一个存放整数的空间,并指定该整数的初徝为100返回一个指向该存储空间的地址
new char[10]; //开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址
new int[5][4]; //开辟一个存放二维整型数组(大小为5*4)的涳间返回首元素的地址

3)new和delete运算符使用的一般格式为:

用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功

//相同 和 不同的地方 new能执行类型构造函数 delete操作符 能执行类的析构函数

    Free不会调用类的析构函数

//2 new 基础类型变量 分配数组变量 分配类对象 ////分配基础类型--混搭没有问题 //相同 和 不同的地方 new能执行类型构造函数 delete操作符 能执行类的析构函数 // malloc free 函数 C 只会分配内存大小 不会调用类的构造析构函数

  • 关键字 static 可以用于说明一个类的成员,
  • 把一个类的成员说奣为 static 时这个类无论有多少个对象被创建,这些对象共享这个 static 成员
  • 静态成员局部于类它不是对象成员
c=c+1; //成员函数访问静态数据成员
  • 静态成員函数数冠以关键字static
  • 静态成员函数提供不依赖于类数据结构的共同操作,它没有this指针
  • 在类外调用静态成员函数用类名 :: ”作限定词或通過对象调用
}

我要回帖

更多关于 求救mday 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信