M语言的源程序有两种格式;脚本M文件和函数M文件【function作为关键词】
函数M文件;输入与输出可变的函数编写;函数间的参数是如何传递的。
输入参数传递:
比如子GUI的名称为subGUI, 设想的参数输入输出为:[out1, out2] = subGUI(in1, in2)
在subGUI的m文件中(由GUIDE自动产生):
1.第一行的形式为:function varargout = subGUI(varargin)
该行不用做任何修改;varargin 和 varargout 分别是一个可变长度的cell数组(MATLAB帮助文件中有说明)。输入参数in1和in2保存在varargin中,输出参数out1,out2包含在varargout中;
2.在subGUI的OpeningFcn中,读入参数,并用guidata保存,即:
handles.in1 = varargin{1};
handles.in2 = varargin{2};
guidata(hObject, handles);
返回参数的设置:
1. 在GUI子程序的OpeningFcn函数的结尾加上uiwait(handles.figure1); figure1是subGUI的Tag;
2. subGUI中控制程序结束(如"OK”和"Cancel"按钮)的callback末尾加上uiresume(handles.figure1),不要将delete命令放在这些callback中;
3. 在子GUI的OutputFcn中设置要传递出去的参数,如 varargout{1} = handles.out1;varargout{2} = handles.out2;末尾添加 delete(handles.figure1); 结束程序。
在GUI的OpenFcn中,如果不加uiwait, 程序会直接运行到下面,执行OutputFcn。也就是说程序一运行,返回值就确定了,再在其它部分对handles.output作更改也没有效果了。
加上uiwait后,只有执行了uiresume后,才会继续执行到OutputFcn,在此之前用户有充分的时间设置返回值。
通过以上设置以后,就可以通过 [out1, out2] = subGUI(in1, in2) 的形式调用该子程序。
在一个GUI中调用另一个GUI时,主GUI不需要特别的设置,同调用普通的函数一样。在打开子GUI界面的同时,主程序还可以响应其它的控件。不需要担心子GUI的返回值被传错了地方。
2. 运用global定义全局变量传递参数(适用于gui内控件间以及不同gui间)
这种方式恐怕是最简单的方式,是很省心!但是但是,简单的问题就在于有时你会很头疼!因为在每一个要到该全局变量的地方,你都要添一句gloal x,还有就是如果你在一个地方修改了
x的值,那么所有x的值就都变了!有的时候恐怕会出现紊乱。另一个更重要的问题在于,套用C++的一句话,全局变量破坏了程序的封装性!所以,全局变量是能少用尽量少用。
3. 运用UserData传递参数(gui内)
直接通过对象的userdata属性进行各个callback之间的数据存取操作。首先必须将数据存储到一个特定的对象中,假设对象的句柄值为ui_handle,需要存储的值为value,则输入以下程序即可:
set('ui_handle','UserData',Value);
此时,value数据就存在句柄值为ui_handle的对象内,在执行的过程中若要取回变量可以通过以下方式在任意callback中获取该数据值:
value=get(''ui_handle,'UserData');
虽然使用这种方法简单,但是每个对象仅能存取一个变量值,因此当同一对象存储两次变量时,先前的变量值就会被覆盖掉,因此都用UserData存储简单与单一的数据。如下面有两个gui函数, myloadfn加载mydata.mat文件,该文件内存储XYData变量,其值为m*2的绘图矩阵,加载后将该变量值存储到 当前的窗口的UserData属性中。另一个myplotfcn函数则是用以获取该UserData属性中存 取的绘图数据,然后绘图。代码如下:
function myloadfcn
load mydata;
set(gcbf,'UserData',XYdata)
function myplotfcn
XYdata=get(gcbf,'UserData');
x=XYData(:,1);
y=XYData(:,2);
plot(x,y);
4.应用setappdata\getappdata与rmappdata函数(gui间和gui内,推荐使用)
使用上面三个函数最有弹性处理数据的传送问题,与UserData的方式相类似,但是克服UserData的缺点,使一个对象能存取多个变量值。
(1)getappdata函数
VALUE=getappdata(H,NAME)
(2)setappdata函数
setappdata(H,NAME,VALUE)
(3)rmappdata
rmappdata(H,NAME)
首先在matlab命令窗口输入magic(3)数据,因此当前的工作空间就存储了magic(3)这组数据了,然后建立一个按钮来获取并显示magic(3)数据
>>A=magic(3);
>>setappdata(gcf,'A','A');%save
>>uicontrol(‘String’,'显示矩阵A','callback','A=getappdata(gcf,'A')');
当在主子gui内调用时,可以如下设置
fig1调用fig2时,使用fig2指令来打开fig2,
在fig2的m文件中,在回调函数中用setappdata(fig1,'A',A)实现返回fig1,并将参数A传递给fig1
然后在fig1的使用A的地方添加A=getappdata(fig1,‘A’)。
但这种方式的一个问题就是没调用一次,fig1的数据就得初始化一次,这是因为setappdata(fig1,'A',A)中出现了fig1,调用一次setappdata就得运行一次fig1的缘故,解决方案就是把
setappdata(fig1,'A',A)改为setappdata(0,'A',A),这样把A读入matlab workspace,相当于一个全局变量了,但当然比直接用global定义全局变量好!
5.结合handles和guidata函数(gui内,不推荐使用,经常出现问题,比如在handles中添加了变量对象Y后可能就会挤掉handles另外一个对象)
他的使用格式如下,如果你在pushbutton1中得到一个变量X,相传出去,那么在pushbutton1的callback中,在得到X后添加如下代码:
handles.X=X;
guidata(hObject,handles)(注意,一定是两行连写)
在pushbutton2中要用到X是,在其callback先添加 X=handles.X;即可得到X的值。
6. 运用save和load(importdata)传递参数(gui内和gui间)
将某变量x的值先存到磁盘,用的时候在调用。格式如下:save('*.mat','x');用的时候就用load('*.mat'),但这样只是把x读到了matlab workspace,不会用显示,你还要再去查看这个变量名, 然后才能用,建议使用p=importdata('*.mat'),p是一个结构体,可以随意使用了。当然,这种方式涉及到磁盘读写,速度当然会有影响的,一般情况不用,通常用在保存以及导入某个变量时!
===================================================
matlab中s函数编写心得(转)
Part I:
所谓s函数是system Function的简称,用它来写自己的simulink模块. s函数可以用matlab、C、C++、Fortran、Ada等语言来写,这儿我只介绍怎样用matlab语言来写吧(主要是它比较简单) < xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />
先讲讲为什么要用
s
函数,我觉得用
s
函数可以利用
matlab
的丰富资源,而不仅仅局限于
simulink
提供的模块,而用
c
或
c++
等语言写的
s
函数还可以实现对硬件端口的操作,
还可以操作
windows API
等
先介绍一下simulink的仿真过程(以便理解s函数),simulink的仿真有两个阶段:一个为初始化,这个阶段主要是设置一些参数,像系统的输入输出个数、状态初值、采样时间等;第二个阶段就是运行阶段,这个阶段里要进行计算输出、更新离散状态、计算连续状态等等,这个阶段需要反复运行,直至结束.
在matlab的workspace里输入edit sfuntmpl(这是matlab自己提供的s函数模板),我们看它来具体分析s函数的结构.
1. 函数的函数头
函数的第一行:
function [sys,x0,str,ts]=sfuntmpl(t,x,u,flag) ,
先讲输入与输出变量的含义:
t
是采样时间,
x
是状态变量,
u
是输入(是做成
simulink
模块的输入),
flag
是仿真过程中的状态标志(以它来判断当前是初始化还是运行等)
sys
输出根据
flag
的不同而不同(下面将结合
flag
来讲
sys
的含义),
x0
是状态变量的初始值,
str
是保留参数(
mathworks
公司还没想好该怎么用它
,
一般在初始化中将它置空就可以了,
str=[]), ts
是一个
1×2
的向量
, ts(1)
是采样周期
, ts(2)
是偏移量
2. 函数分析
下面结合
sfuntmpl.m
中的代码来讲具体的结构:
switch flag, %
判断
flag
,看当前处于哪个状态
case 0,
[sys,x0,str,ts]=mdlInitializeSizes;
// 解释说明
flag=0
表示当前处于初始化状态,此时调用函数
mdlInitializeSizes
进行初始化,此函数在
该文件的第
149
行定义. 其中的参数
sys
是一个结构体,它用来设置模块的一些参数,各个参
数详细说明如下
size = simsizes;%
用于设置模块参数的结构体用
simsizes
来生成
sizes.NumContStates = 0; %
模块连续状态变量的个数
sizes.NumDiscStates = 0; %
模块离散状态变量的个数
sizes.NumOutputs = 0; %
模块输出变量的个数
sizes.NumInputs = 0; %
模块输入变量的个数
sizes.DirFeedthrough = 1; %
模块是否存在直接贯通
sizes.NumSampleTimes = 1; %
模块的采样时间个数, 至少是一个
sys = simsizes(sizes); %
设置完后赋给
sys
输出
举个例子,考虑如下模型:
dx/dt=fc(t,x,u)
也可以用连续状态方程描述:
dx/dt=A*x+B*u
x(k+1)=fd(t,x,u)
也可以用离散状态方程描述:
x(k+1)=H*x(k)+G*u(k)
y=fo(t,x,u)
也可以用输出状态方程描述:
y=C*x+D*u
设上述模型连续状态变量、离散状态变量、输入变量、输出变量均为
1
个,我们就只需改上面那一段代码为(
一般连续状态与离散状态不会一块用, 我这儿是为了方便说明):
sizes.NumContStates=1;sizes.NumDiscStates=1;sizes.NumOutputs=1;sizes.NumInputs=1;
其他的可以不变, 继续在
mdlInitializeSizes
函数中往下看:
x0 = []; %
状态变量设置为空,表示没有状态变量,以我们上面的假设,可改
为
x0=[0,0](
离散和连续的状态变量我们都设它初值为
0)
str = []; %
保留参数, 置
[]
就可以了, 没什么用
ts = [0 0]; %
采样周期设为
0
表示是连续系统, 如果是离散系统在下面的
mdlGetTimeOfNextVarHit
函数中具体介绍
case 1,
sys=mdlDerivatives(t,x,u);
//
flag=1
表示此时要计算连续状态的微分, 即上面提到的
dx/dt=fc(t,x,u)
中的
dx/dt,
找到193行的
函数mdlDerivatives
,
如果设置连续状态变量个数为
0
, 此处只需
sys=[]
就可以了,
按我们上述讨论的那个模型, 此处改成
sys=fc(t,x(1),u)
或
sys=A*x(1)+B*u,
我们这儿
x(1)
是连续状态变量, 而
x(2)
是离散的,
这儿只用到连续的, 此时的输出
sys
就是微分
case 2,
sys=mdlUpdate(t,x,u);
//
flag=2
表示此时要计算下一个离散状态, 即上面提到的
x(k+1)=fd(t,x,u),
找到
mdlUpdate
函数,
它这儿
sys=[]
表示没有离散状态, 我们这儿可以改成
sys=fd(t,x(2),u)
或
sys=H*x(2)+G*u;%sys
即为
x(k+1)
case 3,
sys=mdlOutputs(t,x,u);
//
flag=3
表示此时要计算输出, 即
y=fo(t,x,u),
找到218行的
mdlOutputs
函数.
如果
sys=[]
表示没有输出, 我们改成
sys=fo(t,x,u)
或
sys=C*x+D*u %sys
此时为输出
y
case 4,
sys=mdlGetTimeOfNextVarHit(t,x,u);
//
flag=4
表示此时要计算下一次采样的时间, 只在离散采样系统中有用
(
即上文的
mdlInitializeSizes
中提到的
ts
设置
ts(1)
不为
0),
连续系统中只需在
mdlGetTimeOfNextVarHit
函数中写上
sys=[].
这个函数主要用于变步长的设置, 具体实现大家可以用
edit vsfunc
看
vsfunc.m
这个例子
case 9,
sys=mdlTerminate(t,x,u);
//
flag=9
表示此时系统要结束,一般来说写上在
mdlTerminate
函数中写上
sys=[]
就可, 如
果你在结束时还要设置什么,就在此函数中写
完了.
Part II
此外, s函数还可以带用户参数, 下面给个例子, 它和simulink下的gain模块功能一样
function [sys,x0,str,ts] = sfungain(t,x,u,flag,gain)
switch flag,
case 0,
sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 0;
sizes.NumOutputs = 1;
sizes.NumInputs = 1;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1;
sys = simsizes(sizes);
x0=[];
str=[];
ts=[0,0];
case 3,
sys=gain*u;
case {1,2,4,9},
sys = [];
end
做好了s函数后,simulink --> user-defined function下拖一个S-Function到你的模型, 就可以用了.在simulink --> user-defined function还有个s-Function Builder, 他可以生成用c语言写的s函数. 或者在matlab的workspace下打sfundemos, 可以看到很多演示s函数的程序
Part III
SIMULINK s-function的设计
Simulink为用户提供了许多内置的基本库模块, 通过这些模块进行连接而构成系统的模型. 对于那些经常使用的模块进行组合并封装可以构建出重复使用的新模块, 但它依然是基于Simulink原来提供的内置模块.
而Simulink s-function是一种强大的对模块库进行扩展的新工具.
(一) s-function的概念
s-function是一个动态系统的计算机语言描述, 在MATLAB里, 用户可以选择用m文件编写, 也可以用c或mex文件编写, 在这里只给大家介绍如何用m文件编写s-function.
S-function提供了扩展Simulink模块库的有力工具, 它采用一种特定的调用语法, 使函数和Simulink解法器进行交互.
S-function最广泛的用途是定制用户自己的Simulink模块. 它的形式十分通用, 能够支持连续系统、离散系统和混合系统.
(二) 建立m文件s-function
1. 使用模板文件:sfuntmp1.m, 其格式为[sys,x0]=function(t,x,u,flag). 该该模板文件位于MATLAB根目录下toolbox/simulink/blocks目录下
模板文件里s-function的结构十分简单, 它只为不同的flag的值指定要相应调用的m文件子函数. 比如当flag=3时, 即模块处于计算输出这个仿真阶段时, 相应调用的子函数为sys=mdloutputs(t,x,u). 模板文件使用switch语句来完成这种指定, 当然这种结构并不唯一, 用户也可以使用if语句来完成同样的功能. 而且在实际运用时, 可以根据实际需要来去掉某些值, 因为并不是每个模块都需要经过所有的子函数调用.
模板文件只是Simulink为方便用户而提供的一种参考格式, 并不是编写s-function的语法要求, 用户完全可以改变子函数的名称, 或者直接把代码写在主函数里, 但使用模板文件的好处是, 比较方便, 而且条理清晰.
使用模板编写s-function, 用户只需把s-函数名换成期望的函数名称, 如果需要额外的输入参量, 还需在输入参数列表的后面增加这些参数, 因为前面的4个参数是simulink调用s-function时自动传入的. 对于输出参数, 最好不做修改. 接下去的工作就是根据所编s-function要完成的任务, 用相应的代码去替代模板里各个子函数的代码即可.
Simulink在每个仿真阶段都会对s-function进行调用. 在调用时, Simulink会根据所处的仿真阶段为flag传入不同的值, 而且还会为sys这个返回参数指定不同的角色. 也就是说尽管是相同的sys变量, 但在不同的仿真阶段其意义却不相同, 这种变化由simulink自动完成.
m文件s-function可用的子函数说明如下:
mdlInitializeSizes(flag=0) -- 定义s-function模块的基本特性, 包括采样时间、连续或者离散状态的初始条件和sizes数组
mdlDerivatives(flag=1) -- 计算连续状态变量的微分方程
mdlUpdate(flag=2) -- 更新离散状态、采样时间和主时间步的要求
mdlOutputs(flag=3) -- 计算s-function的输出
mdlGetTimeOfNextVarHit(flag=4) -- 计算下一个采样点的绝对时间, 这个方法仅仅是在用户在mdlInitializeSizes 里说明了一个可变的离散采样时间
概括说来, 建立s-function可以分成两个分离的任务: 第一, 初始化模块特性包括输入输出信号的宽度, 离散连续状态的初始条件和采样时间. 第二, 将算法放到合适的s-function子函数中去。
2. 定义s-function的初始信息
为了让Simulink识别出一个m文件是s-function, 用户必须在s-函数里提供有关s-函数的说明信息, 包括采样时间、连续或者离散状态个数等初始条件. 这一部分主要是在mdlInitializeSizes子函数里完成.
Sizes数组是s-function函数信息的载体, 它内部的字段意义为:
NumContStates(sys(1)):连续状态的个数(状态向量连续部分的宽度)
NumDiscStates(sys(2)):离散状态的个数(状态向量离散部分的宽度)
NumOutputs(sys(3)): 输出变量的个数(输出向量的宽度)
NumInputs(sys(4)):输入变量的个数(输入向量的宽度)
DirFeedthrough(sys(5)):有不连续根的数量
NumSampleTimes(sys(6)):采样时间的个数,有无代数循环标志
如果字段代表的向量宽度为动态可变, 则可以将它们赋值为-1. 注意DirFeedthrough是一个布尔变量, 它的取值只有0和1两种, 0表示没有直接馈入, 此时用户在编写mdlOutputs子函数时就要确保子函数的代码里不出现输入变量u; 1表示有直接馈入. NumSampleTimes表示采样时间的个数, 也就是ts变量的行数, 与用户对ts的定义有关.
需要指出的是, 由于s-function会忽略端口, 所以当有多个输入变量或多个输出变量时, 必须用mux模块或demux模块将多个单一输入合成一个复合输入向量或将一个复合输出向量分解为多个单一输出.
3. 输入和输出参量说明
S-function默认的4个输入参数为t、x、u和flag, 它们的次序不能变动, 代表的意义分别为:
t -- 代表当前的仿真时间, 这个输入参数通常用于决定下一个采样时刻, 或者在多采样速率系统中, 用来区分不同的采样时刻点, 并据此进行不同的处理
x -- 表示状态向量, 这个参数是必须的, 甚至在系统中不存在状态时也是如此. 它具有很灵活的运用
u -- 表示输入向量
flag -- 是一个控制在每一个仿真阶段调用哪一个子函数的参数, 由Simulink在调用时自动取值.
S-function默认的4个返回参数为sys、x0、它们的次序不能变动,代表的意义分别为:
sys -- 是一个通用的返回参数, 它所返回值的意义取决于flag的值
x0 -- 是初始的状态值(没有状态时是一个空矩阵[]), 这个返回参数只在flag值为0时才有效, 其他时候都会被忽略.
假设, 有一系统如下:
dx1=x2
dx2=9.81*sin(x(1))-2*x(2)+u
求出系统在单位阶跃输入下的x1的状态变化曲线, 假设x1,x2初值为0, 则:
function [sys,x0]=dong(t,x,u,flag)
if flag==0
sys=[2;0;2;1;0;0];
x0=[0;0];
elseif flag==1
sys=[x(2);9.81*sin(x(1))-2*x(2)+u];
================================================================
[转载]matlab中遇到的一些问题
http://blog.sciencenet.cn/home.php?mod=space&uid=436588&do=blog&id=320692
================================================================
matlab中varargout与nargout,varargin与nargin的区别
http://bbs.ednchina.com/BLOG_ARTICLE_3003121.HTM
================================================================
=======光标隐藏问题
解决方案:如果你安装到D盘,那么找到d:\matlab7\toolbox\ccslink\ccslink\info.xml 这个文件,用写字板打开这个文件 ,找到有一行这样的<name>Link for Code Composer Studio?/name>,把这句的/name>改成</name>,再保存一下这文件
================================================================
================================================================
================================================================