Anylogic用户手册页)
-CAL-FENGHAI.-(YICAI)-Company One1
-CAL-本页仅作为文档封面,使用请直接删除
总86
(1. 创建AnyLogic模型
AnyLogic建模语言
AnyLogicTM建模语言已经成功应用于对大规模和复杂系统的建模。AnyLogicTM
模型的主要构建模块是活动对象(active object)。活动对象可以用于建模现实世界中类型广泛的各种对象,例如加工工作台,资源,人员,硬件,具体的物体,控制器,等等。
一个活动对象即是活动对象类的一个实例。在你开发一个AnyLogicTM模型时,你实际上是在开发活动对象的类,以及定义这些类之间的关系。你也可以很方便地使用AnyLogicTM库中的活动对象类。
活动对象类被映射到JavaTM类上。因此,活动对象类允许继承,虚函数,多态等等特性。面向对象的方法给建模带来了显著的益处。使用类进行建模提供了结构分解和活动对象重用的特性。在定义了一个具有所需结构的活动对象类之后,你就可以在你的模型中创建此类的多个活动对象。类等级结构允许对上述这些概念进行更进一步的扩展。
TM
活动对象继承
由于活动对象类都是JavaTM类,因此一个活动对象类可以继承自另一个活动对象类。子类继承了父类的接口,并且可以加入自己独有的结构元素和方法。继承允许对代码的重用,并使得对模型的修改变得简单易行。在你定义了基础类之后,例如此基类代表一辆汽车,则它的通用属性可以被子类所继承,例如子类可以分别代表运动型车辆和卡车。
实际上现实世界中的所有对象都具有复杂的结构。为便于管理和掌握大规模系统的复杂结构,分解就成了一条重要原则。通过将一个整体的系统分解为各个部分,并且对这些部分进一步分解,这样我们就克服了人类认知能力的局限。
等级化分解
由于一个活动对象可能在任意所需的深度上封装其他活动对象,因此
AnyLogicTM模型可以等级化地分层分解。由于每个活动对象通常代表模型中的一个逻辑部分,因此你就可以根据需要,将一个模型分解为具有不同细节的多个层次。每个AnyLogicTM模型中都有一个根活动对象,其中包含了被封装起来的其他对象,而这些对象又包含其各自的被封装对象,以此类推。这样,我们就创建了活动对象的等级树。封装也使你能够隐藏被建模对象中的所有复杂细节。
结构分解
2
由于AnyLogic模型都具有定义良好的交互接口,因此这些模型可以被结构化地分解。活动对象只通过边界对象与它们周围的环境进行交互。通过定义连接器以建模实际的耦合关联,我们就可以很方便地描述不同对象之间的关联。这样就将对象的内部实现与关于环境的直接知识分离开,使得活动对象可以重用。
TM
活动对象重用
除了使用继承之外,对包含模型类的库的使用也支持了对建模知识的重用。AnyLogicTM允许你创建可重用的活动对象类库,这些库可以在一些特定的应用领域或建模工作中进行创建。库允许在不同模型中对类的更好的重用。你只需要对一个类开发一次,并进行存储,即可在多个工程中使用这个类。
开始使用AnyLogic
在此后你都将使用AnyLogicTM开发环境开发和运行模型。首先,你需要打开AnyLogicTM,并创建一个新工程,或打开一个已有的工程。接着,你需要使用由AnyLogicTM提供的构建工具构建此模型。然后你就可以运行仿真。
这一章节为你提供了如何开始使用AnyLogicTM的参考信息。
► 打开AnyLogicTM
1. 从Windows开始菜单中打开AnyLogic快捷方式(默认位于如下菜单路径
中:开始|所有程序|AnyLogic |AnyLogic)。 2. 此时即出现注册向导。为使用AnyLogicTM构建模型,你需要拥有试用(有
限时间)或永久的全功能产品密钥。
► 使用试用版AnyLogicTM
1. 获得一个试用版密钥。如果你下载了AnyLogicTM用于评估测试,则这一密
钥将通过电子邮件发送给你。其他情况,请打开如下网页: 2.
3. 并填写其中的表格。然后产品密钥将通过电子邮件发送给你。
4. 打开了注册向导之后,选择向导中的Enter permanent or evaluation key(输入永久或试用密钥)选项,然后输入你通过电子邮件接收到的试用版产品密钥。 5. 为继续运行AnyLogicTM,你可以选择Continue evaluation(继续评估)选
项。
► 获得全功能的AnyLogicTM产品密钥
TM
3
1. 在打开注册向导之后,选择Send request for permanent key(发送永久
密钥请求)选项,然后按照向导提示操作。你将被提示要通过电子邮件发送请求信息到请求处理中心。 2. 在你通过电子邮件接收到你的个人解锁密钥之后,再次打开注册向导(如
有必要,请点击AnyLogicTM的Help(帮助)菜单,选择Register product(产品注册)),接着选择Enter permanent or evaluation key(输入永久或试用密钥)选项,然后输入你的个人解锁密钥。 3. 在完成了产品注册向导之后,AnyLogicTM即开始运行(图1)。
► 运行AnyLogicTM,并打开指定工程
在Windows资源管理器中点击一个AnyLogic工程文件(扩展名为.alp,图标为)。如果你已经完成了产品注册向导,则此时AnyLogicTM应开始运行。如果没有,请先完成产品注册向导,然后再次点击此文件图标。
TM
图 1 AnyLogicTM用户界面
请注意点击另一个模型文件并不会打开一个新的AnyLogicTM窗口。另一个模型文件将在同一个AnyLogicTM窗口中打开(如有必要,你将被提示要保存现在正在打开的文件)。
4
使用工程
在启动之后,AnyLogicTM即显示Start Page(开始页),如图2所示。开始页将提示你创建一个新工程,打开现有工程,或打开一个最新的AnyLogicTM实例。
图2. AnyLogicTM开始页
一个工程即是你在开发模型时的一个工作区。你可以使用开始页或AnyLogicTM
的File(文件)菜单对AnyLogicTM工程进行管理。 ► 创建一个新工程
1. 在开始页的Projects(工程)页面中,点击New project(新建工程)按
钮,或者 2. 点击New(新建)工具条按钮
,或者
3. 从主菜单中选择File|New…(文件|新建),或者 4. 按键盘上的Ctrl+N。
5
5. 此时即出现New project(新建工程)对话框。 6. 指定新工程的名称和保存位置。
7. 指定你是否希望为此工程创建一个文件夹。 8. 点击OK。
► 打开一个现有的工程
1. 在开始页的Projects(工程)页面,点击Browse(浏览)按钮,或者 2. 点击Open(打开)工具条按钮
,或者
3. 从主菜单中选择File|Open…(文件|打开),或者 4. 按键盘上的Ctrl+O。
5. 此时Open(打开)对话框即显示。 6. 浏览找到你希望打开的工程文件, 7. 双击此文件,或者
8. 点击此文件,然后点击Open(打开)按钮。 AnyLogicTM提供了对最近打开过的工程的快捷访问。
► 打开一个最近打开过的工程
1. 在AnyLogicTM的File(文件)菜单底部的工程列表中选择你希望打开的工
程,或者 2. 点击开始页中的Projects(工程)选项卡,从最近打开的工程列表中选择
你希望打开的工程,然后点击Open(打开)按钮。 如果你正在使用某个特定的工程,你可以告诉AnyLogicTM不要在程序启动时显示开始页,而是直接打开你最近使用过的工程。 ► 在AnyLogicTM启动时打开最近使用的工程/开始页
1. 在主菜单中选择Tools|Options…(工具|选项..,)。 2. 此时即出现Options(选项)对话框。
3. 在Miscellaneous(杂项)页面,选择/取消Reload last project on startup(在启动时重新加载前一次使用的工程)选框。 4. 点击OK。
AnyLogicTM标准发行版本中包含了一些最新的范例,这些范例按照主题类别组织(计算机和电信网络,医疗健康,制造和后勤,交通和运输等)。你可以查看这些例子以了解如何开发你自己的模型。
6
► 打开一个AnyLogic范例
1. 在开始页中点击Examples(范例)选项卡。 2. AnyLogicTM范例列表即显示于开始页的右侧面板中。
3. 如有必要,选择By category(按主题)选项,则将这些例子按照
AnyLogicTM主题类别进行排序。范例主题类别的列表显示于右侧面板中,为显示某一类别中的所有范例,请点击此类别项目左侧的加号图标。 4. 如有必要,选择Sorted alphabetically(按字母顺序排序)选项以将范
例按照字母顺序排序。 5. 点击一个范例项目。
6. 此时即显示此范例的描述信息。 7. 点击Open(打开)按钮。
在开始页中,你可以查看AnyLogicTM的在线资源和文档。
► 查看在线资源
1. 在开始页中,点击Online Resources(在线资源)选项卡。 2. AnyLogicTM在线资源和文档列表即显示于开始页右侧面板中。 3. 点击你希望查看的在线资源。 4. 点击Open(打开)按钮。
► 保存当前工程
1. 点击Save(保存)工具条按钮
,或者
TM
2. 在主菜单中选择File|Save(文件|保存),或者 3. 按键盘上的Ctrl+S。
► 保存当前工程到新的文件名中
1. 从主菜单中选择File|Save As…(文件|另存为)。 2. Save As(另存为)对话框即显示。 3. 指定保存此工程的新文件名称和位置。 4. 点击Save(保存)按钮。
► 保存所有工程
1. 点击Save All(全部保存)工具条按钮
,或者
2. 在主菜单中选择File|Save All(文件|全部保存)。
7
► 关闭当前工程
1. 在主菜单中选择File|Close(文件|关闭)。
AnyLogicTM一次可以打开一个工程。然而,你可以运行多个AnyLogicTM窗口,并在不同的窗口中打开不同的模型。 ► 同时运行两个或多个AnyLogicTM窗口
1. 在一个AnyLogicTM实例窗口正在运行时,从Windows开始菜单中打开
AnyLogic快捷方式。 2. 在新打开的AnyLogicTM窗口中,打开你所需的工程。
这样你就可以同时对多个工程进行操作,并可以将一个工程中的类复制到另一个工程中。
编辑工程
AnyLogicTM开发环境构建于最新的Windows用户界面技术之上,其特性包括: 可自定义的窗口,工具条,颜色,图像 鼠标拖放编辑 图表缩放
通过类树在工程中方便地进行浏览 动态检查类型,参数,以及图表语法 图形化高亮显示错误
你可以在多个AnyLogicTM编辑器窗口中对工程进行编辑。在创建了一个新工程之后,Project(工程)窗口和Properties(属性)窗口即显示(请参考图3)。Project(工程)窗口用于创建,查看,和操作模型元素。Properties(属性)窗口用于查看和修改模型元素的属性。这一章节将给出这些窗口的细节描述。
8
结构编辑器(Structure editor)
工程
(Project)窗
口 状态图
(Statechart)
编辑器
图3 用于编辑工程的窗口
动画编辑器(Animation editor)
属性
(Properties)
窗口
代码(Code)窗
口
输出(Output) 窗口
Project(工程)窗口
你可以在Project(工程)窗口(工作区(Workspace)窗口中的一个页面,
如图4所示)中访问多种工程元素,如包,类等等。由于工程的结构是等级化的,因此一个工程将显示为一个树状结构:工程自身构成树的顶层,接着下一层为包,然后下一层是活动对象和消息类,以此类推。工作区的树状视图使得对此工程的浏览十分便捷。
9
图4. Project(工程)窗口
► 显示Project(工程)窗口
1. 点击Project(工程)工具条按钮
,或者
2. 在主菜单中选择View|Project(查看|工程),或者 3. 按键盘上的Alt+0。
对于Project(工程)窗口中的项目,你可以对它们实行一些通用的操作。你可以复制,移动,和删除项目。这样,你就可以方便地管理你的工程。在复制或删除时,你应首先选定一个项目。 ► 选定一个项目
1. 点击这个项目。
10
2. Properties(属性)窗口中即应显示出被选定项目的属性。
► 删除这个项目
1. 点击Delete(删除)工具条按钮
,或者
2. 在主菜单中选择Edit|Delete(编辑|删除),或者
3. 右键点击此项目,然后在弹出菜单中选择Delete(删除),或者 4. 按键盘上的Del键。
► 复制这个项目
1. 点击Copy(复制)工具条按钮
,或者
2. 在主菜单中选择Edit|Copy(编辑|复制),或者
3. 右键点击此项目,然后在弹出菜单中选择Copy(复制),或者 4. 按键盘上的Ctrl+Ins键。
► 剪切这个项目
1. 点击Cut(剪切)工具条按钮
,或者
2. 在主菜单中选择Edit|Cut(编辑|剪切),或者
3. 右键点击此项目,然后在弹出菜单中选择Cut(剪切),或者 4. 按键盘上的Shift+Del键。
► 粘贴这个项目
4. 选择你希望将其粘贴到的父项目。
5. 例如,你可以将一个活动对象类粘贴到一个包中。 6. 点击Paste(粘贴)工具条按钮
,或者
7. 在主菜单中选择Edit|Paste(编辑|粘贴),或者
8. 右键点击父项目,然后在弹出菜单中选择Paste(粘贴),或者 9. 按键盘上的Shift+Ins键。
如有必要,你可以将此工程元素排除在模型之外。这样,你可以在设计时通过将一个元素排除在外来调整你的模型结构,并引入其他模型元素。 ► 从模型中排除/向模型中引入一个项目
1. 右键点击此项目,然后从弹出菜单中选择Exclude from build(从模型中
排除)。此项目的图像即变得模糊/锐利。
11
Properties(属性)窗口
Properties(属性)窗口用于查看和修改当前选定的对象的属性。在你选定了某个对象之后——即,在Project(工程)窗口中,或在图表编辑器窗口中(请查看图表编辑器,通用操作”)选定一个对象——Properties(属性)窗口中(如图5)将显示所选定对象的属性。
图5. Properties(属性)窗口
12
Properties(属性)窗口由若干个页面组成。每个页面中都有如编辑框,选框,按钮等等之类的控件,用于查看和修改属性。页面的数目和每个页面的内容取决于所选定对象的类型。
你可以直接将一个项目从模型树中拖动到Properties(属性)窗口的一个域内。
► 显示/隐藏Properties(属性)窗口
1. 点击Properties(属性)工具条按钮
,或者
2. 在主菜单中选择View|Properties(查看|属性),或者 3. 按键盘上的Alt+Enter键。
► 显示Properties(属性)窗口中的特定页面
1. 点击Properties(属性)窗口顶部的对应选项卡。
每个模型元素都可以有一条描述性文字与之相联系,以使模型更易于理解。
► 设置元素描述
1. 选择模型元素
2. 在Properties(属性)窗口的Description(描述)页面中输入文字。 AnyLogicTM将为当前选定的模型元素显示工具提示,其中显示此对象的属性的细节描述。
► 获得关于一条属性的信息
1. 在Properties(属性)窗口中,将鼠标光标移动到所需的控件上,然后等
待显示工具提示。 如有必要,你可以告诉AnyLogicTM不要显示属性的工具提示。
► 显示/隐藏属性的工具提示
1. 在主菜单中选择Tools|Options...(工具|选项)。 2. 此时即出现Options(选项)对话框。
3. 在Miscellaneous(杂项)页面中,选中/取消Enable property tips(允
许属性提示)选框。 4. 点击OK。
13
对窗口进行布局
在编辑你的工程时,你实际上是在若干个窗口中进行工作。所打开的窗口的名称列表显示于AnyLogicTM的Windows菜单的底部。你可以使用Window菜单的选项对打开的窗口进行布局。 ► 以层叠方式显示模型窗口
1. 在主菜单中选择Window|Cascade(窗口|层叠)。
► 将模型窗口沿着AnyLogicTM窗口宽度方向纵向平铺
1. 在主菜单中选择Window|Tile Vertically(窗口|纵向平铺)。
► 将模型窗口沿着AnyLogic窗口长度方向横向平铺
1. 在主菜单中选择Window|Tile Horizontally(窗口|横向平铺)。
► 关闭所有窗口
1. 在主菜单中选择Window|Close All(窗口|关闭所有窗口)。
► 激活一个窗口
1. 从Window(窗口)菜单中选择此窗口的名称。
2. 如果打开了太多的窗口,则窗口列表中只显示其中的一部分。在主菜单中
选择Window|More Windows…(窗口|更多窗口),在Select Window(选择窗口)对话框中选择你希望激活的窗口,然后点击OK。
► 激活列表中的下一个窗口
1. 在主菜单中选择Window|Next(窗口|下一个窗口),或者 2. 按键盘上的Ctrl+F6。
► 激活列表中的上一个窗口
1. 在主菜单中选择Window|Previous(窗口|上一个窗口),或者 2. 按键盘上的Ctrl+Shift+F6。
TM
模型元素
AnyLogicTM模型是等级化地组织起来的。工程(project)由包(package)组成,以便更好地组织一个工程的结构。一个工程可以使用其他工程作为库
(library)——库是一组针对特定应用领域而开发的类的集合。为使你的工作更
14
加容易,AnyLogic允许你根据你需要对模型进行的实验,指定若干个对应于不同模型执行参数的实验(experiment)。
这一章节将对这些AnyLogicTM模型元素进行介绍。
TM
工程
AnyLogicTM中的一个工作单元即称为一个工程。在一个工程中完整地定义了一个模型或一个库。一个工程在Project(工程)窗口中将显示为一个根项目。 下面所述的工程属性定义于Properties(属性)窗口的General(常规)页面中。
常规属性
Name(名称)——工程的名称,通常与模型的文件名相同。 Loaded from(加载位置)——[只读]工程文件(.alp)的位置。 Target file(目标文件)——[可选]存储所生成的代码的文件的文件名。如果你希望将一个工程作为库来使用,则你需要指定此属性,请参考第20章“库”。
Additional library files(附加的库文件)——[可选]你所希望在编译时加入到此工程的JavaTM库列表,由分号分隔。
Folder for generated files(放置所生成的文件的文件夹)——[可选]AnyLogicTM存放所生成的文件的文件夹的路径。如果未指定,则AnyLogicTM将所生成的文件放置于Windows临时文件夹中。
AnyLogic可以为整个工程生成一个HTML报告。编辑器可以生成综合的交叉引用的HTML报告,其中包括图表,元素属性,和代码。为打印整个报告,你可以从浏览器中打印此HTML报告。 ► 生成整个工程的HTML报告
1. 在主菜单中选择File|Generate Report…(文件|生成报告)。 2. 此时即打开浏览器,并显示所生成的.html报告。
包
工程由包组成。在工程中可以有一个或多个包。包中含有活动对象,消息,其他类,和外部文件。包可以用于更好地对工程的结构进行组织。 ► 向工程中加入一个新的包
1. 在主菜单中选择Insert|New Package(插入|新的包),或者
15
2. 在Project(工程)窗口中,右键点击此工程,然后从弹出菜单中选择New Package…(新建包) 3. 此时即打开New Package(新建包)对话框。 4. 指定新建的包的名称,然后点击OK。 属性
Name(名称)——此包的名称。
Exclude from build(构建时排除)——如果设置此属性,则此包将被排除出此模型。
当AnyLogicTM生成代码时,它把每个AnyLogicTM包映射到同名的JavaTM包上。因此,位于不同的AnyLogicTM包中的类被放置到不同的JavaTM包中。使用
AnyLogicTM包的规则与使用JavaTM包的规则相同。为使用一个来自于另一个包的类,你需要导入此包,或者在这个类的名称前面添加此包名称作为前缀。包的导入将在“导入包”中介绍。
如果你不希望与名字空间打交道,你可以在你的模型中只使用一个包——例如,mypackage。默认情况下,在你创建一个新工程时,AnyLogicTM即创建一个与此工程同名的包。
库
一个工程可以将其他工程作为库来使用。库是为特定应用领域或建模任务所开发的类的集合。AnyLogicTM中提供了若干个库,你也可以很容易地创建你自己的库。
使用库具有几个优点:
提供了在不同模型中对类的更好的重用。一个类只需要被开发和存储一次,就可以在其他工程中被引用使用。
库使你可以在AnyLogicTM工程中组织团队工作:模型的一部分由一个团队成员开发,并放到库中,其他人在他们的工作只需使用相兼容的库版本。 通过开发合适的库,你可以将AnyLogicTM转化成针对特定领域的高层次的建模工具,在此工具中可以通过简易的鼠标点击来进行操作。
AnyLogicTM在Libraries(库)窗口中显示了可用的库。AnyLogicTM标准发行版本中包含了若干个库,这些库位于Lib目录下。你可以查看这些库以了解如何开发你自己的库。创建库和使用AnyLogicTM库类的细节信息将在第20章“库和外部文件”中给出。
16
实验
一个实验(experiment)中存储了模型的一组配置参数。AnyLogicTM支持几种不同的实验类型,以用于不同的仿真任务。
当创建一个新工程时,AnyLogicTM即自动创建一个实验,并将其设置为当前实验(current experiment),即定义了当前模型仿真参数的实验。这一实验是一个仿真实验(simulation experiment)。它将运行模型仿真,并显示动画,同时允许对模型进行调试。大多数情况下使用的实验都是仿真实验。其他的AnyLogicTM实验类型(优化实验optimization experiment,参数变化实验parameter variation experiment)只用于模型参数起重要作用,并且你需要分析这些参数如何影响模型行为的情形,或你希望找到你模型对应的最优参数的情形下。自定义参数(custom parameter)允许你使用JavaTM语言定义自定义的实验脚本。实验和配置参数具体将在第12章“实验”中进行介绍。
活动对象
活动对象是AnyLogicTM模型的主要构建模块。活动对象可以用于建模现实世界中类型广泛的各种对象,例如:加工工作台,资源,人员,硬件,具体的物体,控制器,等等。
一个活动对象是一个活动对象类的一个实例。活动对象类可以由用户开发,或者从库中得到。
► 向包中加入一个新的活动对象类
1. 点击New Active Object Class(新活动对象类)工具条按钮,或者 2. 在主菜单中选择Insert|New Active Object Class(插入|新活动对象
类)。 3. 此时即应出现New Active Object Class(新活动对象类)对话框。 4. 指定所要创建的活动对象类的名称,选择将要放置此活动对象类的包,然
后点击OK。 5. 你也可以在Project(工程)窗口中,用鼠标右键点击将要加入活动对象
类的包,然后在弹出菜单中选择New Active Object Class(新活动对象类)菜单项。 6. 此时即应出现New Active Object Class(新活动对象类)对话框。 7. 在此对话框中指定新的活动对象类的名称,然后点击OK。 每个活动对象类都有如下属性: 属性
17
Class name(类名称)——此类的名称。
Base class(基类)——[可选]基类的名称。可以为ActiveObject或它的子类。如果未指定,则认为基类为ActiveObject。请查看,“活动对象继承”,以了解关于活动对象继承的更多信息。
Parameters(参数)——[可选]活动对象类的一组形式参数。
Exclude from build(构建时排除)——如果设置了此属性,则此类被从此工程中排除出去。
Show name(显示名称)——如果设置了此属性,则此类的名称将显示于其结构图中。
Show object rectangle(显示对象矩形)——如果设置了此属性,则代表此对象的边界的矩形将显示于其结构图中。
Public(exported from library)——如果此属性未被设置,则在此对象被用作库的情况下,你将无法从其他工程中访问此类(如果你需要隐藏一些辅助库类,你可能需要作此设置)。
结构图
每个活动对象类都有一个与之相联系的结构图。结构图有若干个作用,它可以:
定义活动对象类的接口
定义被封装的类以及它们之间的相互作用 定义行为元素,例如定时器和状态图
结构图由各种不同的形体构成,即:当前对象(this object),被封装的对象(encapsulated object),端口(port),变量(variable),连接器
(connector),图表定时器(chart timer),状态图(statechart),和文本框(text box)(请参考图6)。
18
图6. 结构图
你可以在结构图编辑器中使用结构工具条对活动对象的结构图进行编辑(图7)。
结构图编辑器
19
图7. 结构图编辑器和工具条
► 打开一个活动对象类的结构图
1. 在Project(工程)窗口中右键点击一个活动对象类,然后在弹出菜单中
选择Open Structure(打开结构图),或者 2. 在Project(工程)窗口中双击此活动对象类。
活动对象显示为一个黑体画框。画框代表活动对象类在结构图中的“边界”。这一形体表示,位于此画框中的所有端口和变量都成为此活动对象类的接口元素。这一形体在图中是可选的(非必需)。这一形体的属性既是活动对象类的属性。
你可以使用文本框在图中放置一条注释。这样做不会影响模型的行为。
► 加入一个文本框
1. 点击Text Box(文本框)
工具条按钮,或者
2. 在主菜单中选择Draw|Text Box(绘制|文本框)。 3. 在图中点击你希望放置此文本框的位置。 4. 然后拖动以设置文本框形体的大小。
► 修改文本框中的注释
1. 双击此文本框。 2. 编辑此文本框中的内容。
3. 点击图中的空白区域,或按Esc键,以保存修改后的文字。
4. 你也可以使用文本框的Properties(属性)窗口来修改其中的文字。
图表编辑器 通用操作
AnyLogicTM中有四个图表编辑器:结构图编辑器,状态图编辑器,动画编辑器,以及3D动画编辑器。这些编辑器都是基于同样的技术构建的,因此它们具有一些共同的通用编辑操作,我们将在这一节中介绍这些通用操作。各个编辑器独有的操作分别在第节“结构图”,第节“状态图”,第节“动画图”和第节“3D动画图”中介绍。
AnyLogicTM图表由图形对象——即形体——组成。为绘制一个形体,你需要点击对应的工具条按钮,然后在图中放置此形体。每个编辑器都有自己对应的工具条,其中有此图表类型所特有的形体工具条按钮。
选择形体
在图表中你可以选择任一形体。在你选择了一个形体之后,Properties(属性)窗口中即显示此形体的属性。
20
► 选择一个形体
1. 点击此形体。
► 选择一个以上的形体
1. 拖动矩形选择框以选择多个形体。
► 将形体加入到选择中/从选择中去掉一个形体
1. 按下Shift键,同时用鼠标点击此形体。
► 选择图中的所有形体
1. 从主菜单中选择Edit|Select All(编辑|全选),或者 2. 按Ctrl+A键。 复制,移动,和删除形体 你可以复制,移动,和删除形体。
► 复制所选内容到剪贴板
1. 点击Copy(复制)工具条按钮,或者
2. 在主菜单中选择Edit|Copy(编辑|复制),或者
3. 右键点击所选内容,然后从弹出菜单中选择Copy(复制),或者 4. 按Ctrl+Ins键。
► 剪切所选内容
1. 点击Cut(剪切)工具条按钮
,或者
2. 在主菜单中选择Edit|Cut(编辑|剪切),或者
3. 右键点击所选内容,然后从弹出菜单中选择Cut(剪切),或者 4. 按Shift+Del键。
► 粘贴剪贴板中的内容
1. 点击Paste(粘贴)工具条按钮
,或者
2. 在主菜单中选择Edit|Paste(编辑|粘贴),或者
3. 右键点击图中的空白区域,从弹出菜单中选择Paste(粘贴),或者 4. 按Shift+Ins键。
5. 被粘贴的形体即显示,并且其轮廓线为蓝色。 6. 将被粘贴的形体移动到所需位置。
21
► 复制所选内容
1. 按下Ctrl键,同时拖动所选内容。
► 移动所选内容
1. 拖动所选内容,或者 2. 使用方向键。
► 删除所选内容
1. 点击Delete(删除)工具条按钮
,或者
2. 在主菜单中选择Edit|Delete(编辑|删除),或者
3. 右键点击所选内容,然后从弹出菜单中选择Delete(删除),或者 4. 按Del键。
► 隐藏所选内容
1. 在主菜单中选择Draw|Hide(绘制|隐藏)。
► 取消隐藏所有被隐藏的形体
1. 在主菜单中选择Draw|Unhide All(绘制|取消隐藏所有)。
► 将整个图表的图像复制到剪贴板
1. 在主菜单中选择Draw|Copy Image(绘制|复制图像),或者
2. 右键点击图中的空白区域,然后从弹出菜单中选择Copy Image(复制图
像)。 你可以取消前一个操作。
► 取消前一个操作
1. 点击Undo(取消)工具条按钮
,或者
2. 在主菜单中选择Edit|Undo(编辑|取消),或者 3. 按Alt+Backspace键,或者Ctrl+Z键。
► 重复前一个被取消的动作
1. 点击Redo(重复)工具条按钮,或者
2. 在主菜单中选择Edit|Redo(编辑|重复),或者 3. 按Ctrl+Y键。
你可以移动,中心放置,或缩放图表,以更好地观察图表中的特定部分。
22
► 移动图表
1. 用右键点击图表,然后一直按下右键,移动鼠标。
► 中心放置图表
1. 在主菜单中选择Draw|Go to Center(绘制|移动到中心),或者 2. 右键点击图中的空白区域,然后从弹出菜单中选择Go to Center(移动至
中心)。 3. 图表即被中心放置。
► 缩放图表以适合所有形体
1. 在主菜单中选择Draw|Zoom|Zoom to Fit(绘制|缩放|缩放到合适大
小),或者 2. 右键点击图中的空白区域,然后从弹出菜单中选择Zoom to Fit(缩放到
合适大小)。 3. 此时图表即被中心放置,并且缩放到合适大小以适合所有形体。
► 放大图表
1. 点击Zoom In(放大)工具条按钮
,或者
2. 在主菜单中选择Draw|Zoom|Zoom In(绘制|缩放|放大)。
► 缩小图表
1. 点击Zoom Out(缩小)工具条按钮,或者
2. 在主菜单中选择Draw|Zoom|Zoom Out(绘制|缩放|缩小)。
► 缩放到指定的矩形
1. 在主菜单中选择Draw|Zoom|Zoom to Rectangle(绘制|缩放|缩放到矩
形)。 2. 在图中你希望缩放至的区域拖动鼠标以选择此矩形区域。
► 缩放到默认大小
1. 在主菜单中选择Draw|Zoom|Zoom to Default(绘制|缩放|缩放到默认大
小)。 你可以控制图表网格的外观。 ► 启用/关闭网格
1. 点击Enable Grid(启用网格)工具条按钮
,或者
23
2. 在主菜单中选择Draw|Grid|Enable Grid(绘制|网格|启用网格)。
► 显示/隐藏网格
1. 在主菜单中选择Draw|Grid|Show Grid(绘制|网格|显示网格)。
► 将一个形体对齐到网格上
1. 选择一个形体。
2. 点击Snap to Grid(与网格对齐)工具条按钮,或者
3. 在主菜单中选择Draw|Grid|Snap to Grid(绘制|网格|与网格对齐)。 默认情况下,当你缩放,拖动,或移动一个形体时,其他与之逻辑关联的形体也将发生移动。例如,连接器与端口一起移动,被封装的对象与封装对象一起移动,简单状态将反映复合状态的改变,等等。有时候我们不想要这样的行为,这种情况下你通常可以关闭智能拖动特性。 ► 在操作时关闭智能拖动
1. 在完成操作时按住Shift键。
► 编辑一个形体的名称
1. 双击此形体的名称,或者
2. 右键点击此形体,然后从弹出菜单中选择Edit Name(编辑名称),或者
按F2。 3. 输入此形体的新名称。
4. 按Enter或点击图中的空白区域以保存修改后的名称,或按Esc以取消修
改。 你也可以通过Properties(属性)窗口来编辑形体的名称。
► 旋转一个形体
1. 在主菜单中选择Draw|Rotate(绘制|旋转)。 2. 使用旋转手柄来旋转一个结构元素。
► 获得形体属性的简要信息
1. 将鼠标光标移动到此形体上,并等待出现工具提示。
活动对象的图标
每个活动对象类都有自己特有的图标。每当这个类的实例在结构图中或在动画图(请参考节“结构图动画”)中显示为被封装的对象时,即显示此图标。请注意
24
这一图标图像与AnyLogic动画无关,并且不显示于此活动对象类自身的结构图中。
图标图
活动对象图标由图标图定义。你可以使用动画工具条在图标编辑器(图8)中对图标图进行编辑。
TM
图8. 图标编辑器
► 创建一个活动对象类的图标
1. 点击New Icon(新建图标)工具条按钮,或者 2. 在主菜单中选择Insert|New Icon…(插入|新图标)。 3. 此时即显示New Icon(新建图标)对话框窗口。
4. 指定新图标的名称,选择此图标将要对应的活动对象类,然后点击OK。 5. 你也可以在Project(工程)窗口中,右键点击此图标将要对应的活动对
象类,然后从弹出菜单中选择New Icon…(新建图标)。 6. 此时即显示New Icon(新建图标)对话框窗口。 7. 指定新图标的名称,然后点击OK。 8. 此时即出现图标编辑器窗口。
每个活动对象类都只能有一个对应的图标。
► 打开活动对象类的现有图标
1. 在Project(工程)窗口中,右键点击活动对象类的图标(Icon)项目,
然后从弹出菜单中选择Open Icon(打开图标)。 2. 此时即显示图标编辑器窗口。
25
图标编辑器具有节“图表编辑器,通用操作”中所描述的通用编辑操作。 蓝色十字表示图标图的原点(0, 0)。
一个图标由多个形体,例如圆圈,矩形,线段,以及标记等,组合绘制而成。请查看节“动画形体”和节“标记”以了解关于这些形体的细节描述。图标大小将自动设置以适合其中所有的形体。
每个形体都有一组属性,以定义其视觉外观:位置,高度,宽度,颜色,等等。形体的通用属性将在节“动画形体的通用属性”中介绍。
图标动画概念
每个形体都具有许多属性以定义其视觉外观,这些属性包括:位置,高度,宽度,颜色,等等。典型情况下这些属性将按照如图9所示进行组织:
图9. 图标形体的属性
这些概念与AnyLogicTM动画概念类似——图标图将形体的属性与活动对象的数据联系起来。
左侧的静态值显示了在编辑器中进行绘制时所定义的此属性的值。这一值也将作为默认值。右侧的表达式定义了在仿真过程中这一属性的实际值。在这里你可以将形体的外观与活动对象的任意数据联系起来。数据可以发生改变,并且这些改变将在图中反映出来。如果这一表达式为空,则在整个仿真过程中此属性的值将一直保留为默认的静态值。
图10显示了一个将图标形体的图形属性与活动对象数据相联系起来的例子。这里圆圈的坐标由活动对象的参数x和y动态定义,矩形的旋转角度由活动对象的成员变量alpha定义。
26
图10. 将图形属性与模型数据相联系起来
这样,通过将形体属性与活动对象数据相联系起来,你就可以在模型运行时在结构图动画中动态地显示活动对象。
活动对象的图像
活动对象图标是AnyLogicTM5的新特性。在以前版本的AnyLogicTM中,你只能在来自于文件的静态图像与活动对象类之间建立关联。
实际上,在这一版本中保留活动对象图像特性的目的只是为了与较早的版本相兼容。我们推荐你为活动对象类创建图标,然后将图像形体加到此图标中,而不是直接使用活动对象图像。请注意,如果定义了活动对象类的图标,则活动对象类的图像不起作用。
活动对象的图像通过活动对象的Properties(属性)窗口的Image(图像)页面定义(如图11)。
27
图11. 活动对象Properties(属性)窗口的Image(图像)页面
► 为活动对象定义一个图像
1. 在Project(工程)窗口中点击此活动对象。
2. 点击Properties(属性)窗口的Image(图像)页面中的Image(图像)
按钮。 3. 此时即显示Choose Image(选择图像)对话框。此对话框中显示了预定义
的图像。 4. 为使用一个预定义的图像: 5. 双击此图像,或者 6. 点击此图像,然后点击OK。 7. 如果需要从文件加载图像: 8. 点击Browse(浏览)按钮。 9. 此时即打开Open(打开)对话框。 10. 浏览找到你希望使用的图像文件。 11. 双击此文件,或者
12. 点击此文件,然后点击Open(打开)按钮,以选择此文件。
所指定的图像即显示于Properties(属性)窗口的Image(图像)页面中。
► 移除已指定的活动对象的图像
28
1. 在Project(工程)窗口中点击此活动对象类。
2. 点击Properties(属性)窗口中的Image(图像)页面内的Reset(复
位)按钮。 被封装的对象
活动对象可以在任意所需的深度层次上封装其他活动对象。被封装的对象是其他活动对象类的实例,并且将被此活动对象类的每个实例封装。封装一个类是创建模型等级结构的必须步骤。
► 向一个活动对象类中加入一个被封装的对象
1. 将活动对象类从Project(工程)窗口中拖动到父活动对象的结构图中。 如果为父活动对象定义了形体,则所有的被封装对象都应放置于此父对象形体内部。
被封装的对象显示为被填充的矩形(如图12所示)。如果AnyLogicTM无法找到所引用的类,则被封装的对象将显示为红色。
图12 被封装的对象
被封装的对象具有如下属性 属性
Name(名称)——被封装的对象的名称。 Type(类型)——[只读]被封装的对象所属的类。
Parameters(参数)——[可选]被封装的对象的一系列形式参数。每个参数都应以如下形式给出:Name Value,其中Name是参数的名称,Value是参数的值。
Exclude from build(构建时排除)——如果设置了此属性,则此被封装的对象被排除出模型。
Show name(显示名称)——如果设置了此属性,则此被封装的对象的名称将显示于结构图中。
29
Auto create(自动创建)——如果设置了此属性,则AnyLogicTM将自动创建被封装的对象。否则这一对象应通过手动创建。 你可以打开被封装对象类的结构图。
► 打开被封装对象的结构图
1. 双击被封装的对象,或者
2. 右键点击被封装的对象,从弹出菜单中选择Open Structure(打开结构
图)。 如有必要,你可以在结构图中翻转被封装对象的图像。
► 水平翻转被封装对象
1. 选中此被封装的对象
2. 点击Flip Horizontal(水平翻转)工具条按钮
,或者
3. 在结构图中右键点击被封装的对象,然后从弹出菜单中选择Flip Horizontal(水平翻转),或者 4. 在主菜单中选择Draw|Flip Horizontal(绘制|水平翻转)。
被封装的对象可以为单一对象,或者复数对象(请不要将这个概念与模型重复混淆)。一个复数对象代表一组属于同一类的活动对象。对象重复使你可以非常经济地表述由具有任意相互连接的对象所组成的复杂结构。在父类的结构图中,显示的复数对象名称后面将加上一个星号(如图12)。请查看第2章“复数对象”,以了解关于复数对象的细节描述。
根对象
一个AnyLogicTM模型是由互相封装的活动对象类所构成的一棵树(如图
13)。由于每个活动对象通常代表模型中的一个逻辑部分,因此一个模型可以被分解到若干个细节层次。树的根称之为根对象。根对象代表了你的模型中的最高抽象层次。当你指定根对象的类时,你即告诉了AnyLogicTM在何处开始创建模型。
30
图13. 活动对象树
由于你可以修改模型的根对象,这样AnyLogicTM就可以支持简单的模型修改方法。你可以在同一个工程中创建若干个具有不同根对象的实验。这样你就可以通过改变当前实验来方便地调整你的模型结构。 ► 为一个实验设置根对象
1. 在Project(工程)窗口中点击此实验。
2. 在Properties(属性)窗口,从Root object(根对象)下拉列表中选择
此实验的根对象。 例如,你可以建模一辆汽车。你定义了Automobile类,这个类代表了你的模型中的最高抽象层次,因此你设置这个类为根对象类。此类中封装了代表汽车零部件的对象:轮胎,发动机,化油器,等等。这些部件也可以封装其他代表其中零件的对象,依此类推。然而,你可能需要将注意力集中在汽车的发动机上。因此你可以简单地设置Engine类为你模型的根对象类。反之亦然,你可能需要建模一个车库。这种情况下你需要在你的模型中创建新的抽象层次,并将其设置为模型等级树的顶层。与其他一些已对模型根对象进行详细定义的建模工具不同,在AnyLogicTM中你可以用非常简单的方法改变模型的结构。例如,在上面所述的例子中,进行如下操作:
1. 定义类Garage,以代表车库。
2. 将已经创建好的代表汽车的类封装到Garage类中。 3. 创建一个新的仿真实验,并将它设置为当前实验。 4. 将类Garage作为所创建的实验的根对象类。
31
活动对象的数据
你可以通过定义参数和变量来定义活动对象的数据。你也可以通过编写你自己的JavaTM代码来定义类成员变量。
参数
活动对象可以有参数。通常情况下,参数用于参数化地表示对象。当对象实例具有类中所描述的相同行为,但行为的参数值不同时,即需要使用这些参数。所有的参数在模型执行过程中都可见并且可以更改。这样你就可以在运行时通过更改参数来方便地调整你的模型。活动对象参数可以被关联到被封装的对象的参数上。这种情况下,参数的改变即被沿着活动对象树中的参数依赖关系传播下去。请查看第3章“参数”以了解对参数的细节的描述。
如果你需要建模一些数据单元随时间的连续变化,请使用变量,而不是参数。 变量
如果你需要定义一些数据单元(可能会随时间连续变化),你可以定义一个变量。一个变量可以为任意的标量类型,矩阵,或超矩阵。变量可以与其他活动对象共享。变量可以出现于随时间连续变化的微分和代数方程式,以及模型值中。在模型执行时,可以在AnyLogicTM用户界面中对变量进行观察,并且可以通过用户界面更改变量。请查看第4章“变量”以了解对变量的细节的描述。
类成员变量
你可以在活动对象类的代码窗口的Additional class code(附加的类代码)段声明JavaTM成员变量。你可以在这一对象中访问这些数据成员。请查看为活动对象编辑代码”以了解细节信息。
如果你只需要在一个活动对象内部,且只在离散的时刻(即,既不与其他对象共享,亦不会连续变化)对一个数据项进行访问,且你不需要在模型执行时观察或更改此数据项,则你可以声明一个成员变量。其他情况,请声明一个普通变量。
活动对象的行为
活动对象可以具有内部的行为。在AnyLogicTM中你可以定义离散时间行为,连续时间行为,以及混合行为。
连续的过程用具有连续变化变量的微分和代数方程来描述。
在非常简单的情况下,对象内部的离散行为可以使用定时器来定义;在事件和时间顺序变得更为复杂的时候可以使用状态图(扩展的状态机)来定义。
当离散和连续时间行为之间存在相互依赖关系时,则需要混合模型。你可以使用混合状态图来定义混合的行为。
32
方程式
连续时间的行为可以通过方程式来定义。你可以定义一组微分方程,代数方程,和公式,以描述变量随时间的连续变化。请查看第5章“方程式”以了解关于方程式的细节描述。
定时器
对象内部的行为可以用定时器来定义。定时器用于计划一些用户定义的行为。在AnyLogicTM中有静态和动态两种定时器。后者用于计划多重事件。请查看第8章“定时器”,以了解关于定时器使用的细节描述。
状态图
在活动对象的生命期内,活动对象将对外部及内部事件和条件作出反应,执行操作。活动对象内部存在状态,即表明执行操作的顺序起重要作用。对某些对象,这一操作的事件顺序和时间顺序十分普遍,使得最佳的选择是使用状态转换图——状态图——来描述这些对象的行为。状态图用于显示给定某一给定算法的状态空间,导致从一个状态到另一个状态转变的事件,以及由于状态转变引起的行为。AnyLogicTM支持混合状态图——这是将离散逻辑和连续事件行为结合起来的最自然最有效的方法。在混合状态图中,你可以将一组方程式与状态图的一个状态相关联。状态转换将使连续行为发生改变。同时,你可以指定一个由连续变化变量决定的条件来触发一个转变。连续过程将驱动离散逻辑。请查看第9章“状态图”以了解对状态图的细节描述。
活动对象之间的相互作用
AnyLogicTM支持连续时间和离散时间的活动对象相互作用机制。结合这些机制,你可以创建活动对象的复杂接口。
变量共享
变量共享是AnyLogicTM中的连续时间相互作用机制。这些变量可以暴露于活动对象的接口之中,并且与其他活动对象共享。当属于不同活动对象的两个接口变量被关联到一起时,一个变量的(设置为输出)变化将立刻传播到另一个变量(设置为输入)那里。这就提供了连续和/或离散时间的对象相互作用。请参考第4章“变量”以了解关于变量和变量共享的细节信息。
消息传递
消息传递是AnyLogicTM中的离散时间相互作用机制。这一机制的概念是在活动对象之间传递数据单元——消息。消息在活动对象的特殊元素——端口——之间传递,并且被沿着连接线进行导向,这些连接线将端口连接起来。消息传递可以建模通知或信号机制——在这种情况下,消息代表控制系统中被传递的命令或信号;消息传递也可以建模实体流——在这种情况下,消息用于建模现实世界中的不同对
33
象,例如,产品,人员,卡车等等,或者网络中被传输的数据包。请参考第7章“消息传递”,以了解对端口和消息传递的细节描述。
在对象之间建立相互作用
为在对象之间建立相互作用,你需要使用连接器将不同活动对象上的对应接口元素连接起来。一个连接器是一条连接两个端口或两个变量的线条。在AnyLogicTM中,连接器用于创建拓扑结构。将两个端口连接起来即代表消息将在它们之间传递。将变量连接起来即表明这些变量在任意时刻都将具有相同的值(输出变量的值将被传递到输入变量那里)。
接口元素在结构图中显示为被封装对象的边界上的小形体(请查看图14)。端口显示为方块,变量显示为三角形(指向对象内部的三角形代表输入变量,指向对象外部的三角形代表输出变量)。由于界面元素反映了一个被封装对象类的接口,因此你不能添加,删除,或移动界面元素。
图14 一个被封装对象的接口元素
被封装对象的接口元素具有如下属性: 属性
Name(名称)——[只读]此接口元素的名称
Show name(显示名称)——如果设置了此属性,则在结构他中将显示此接口元素的名称。
► 连接被封装对象的接口元素
1. 拖动一个被封装对象的接口元素到另一个被封装对象的接口元素上,或者 2. 点击Connector(连接器)工具条按钮
击第二个接口元素,或者
,点击第一个接口元素,然后点
3. 在主菜单中选择Draw|Structure|Connector(绘制|结构|连接器),点击
第一个接口元素,然后点击第二个接口元素。 4. 此时即出现连接两个接口元素的连接器(如图15)。
34
图15. 被连接起来的被封装对象的接口元素
一个连接器有如下属性: 属性
Name(名称)——[可选]此连接器的名称
Exclude from build(构建时排除)——如果设置了此属性,则此连接器被从此工程中排除。
Show name(显示名称)——如果设置了此属性,则在结构图中将显示此连接器的名称。
你可以通过编辑一个连接器的显著点(salient point)来编辑此连接器的外观。 ► 加入一个显著点
1. 选择此连接器。
2. 点击Edit Points(编辑点)
工具条按钮,或者
3. 在主菜单中选择Draw|Edit Points(绘制|编辑点),或者
4. 右键点击此连接器,然后在弹出菜单中选择Edit Points(编辑点)。 5. 此时连接器上的点即应变为黄色。
6. 拖动此连接器的一段,以创建一个显著点,或者
7. 右键点击此连接器,然后在弹出菜单中选择Add Point(增加点)。
► 移动一个显著点
1. 拖动此点。
► 移除一个显著点
1. 选择此连接器
2. 点击Edit Points(编辑点)工具条按钮
,或者
35
3. 在主菜单中选择Draw|Edit Points(绘制|编辑点),或者
4. 右键点击此连接器,然后在弹出菜单中选择Edit Points(编辑点)。 5. 右键点击此点,然后在弹出菜单中选择Delete Point(删除点),或者 6. 拖动此点到连接器上的一个临近的点上。 7. 被拖动的点即消失。
被封装对象的接口元素可以被导出到父对象类的接口中。这意味着对应的接口元素即被加入到父对象的接口上,并且被连接到被输出的元素上。这样被封装的对象就可以借助通过已连接端口传递消息的方法或借助传播已连接的对象变化的方法与其父对象进行相互作用。
► 将被封装对象的一个接口元素导出到其父对象的接口上
1. 右键点击此接口元素,然后在弹出菜单中选择Export to Parent(导出到
父对象)。父类的新接口元素即被创建,并且连接到被封装对象的被导出接口元素上。
编辑活动对象的代码
你可以为你的活动对象编写你自己的JavaTM代码,这些代码将在不同的情况下执行。你可以在与此活动对象对应的代码窗口中编辑此活动对象类的代码。 ► 打开一个活动对象类的代码窗口
1. 在Project(工程)窗口中,右键点击工作区树中此对象类子树中的Code(代码)项目,然后在弹出菜单中选择Open Code(打开代码),或者 2. 双击工作区树中此对象类子树中的Code(代码)项目。 3. 此时即显示此活动对象类的代码窗口。(如图16)
36
图16. 活动对象类的代码窗口
活动对象的代码类窗口中有如下段:
Import(导入)——正确编译类代码所需要的import声明。当生成JavaTM代码时,这些声明即被插入到JavaTM类的定义之前。
Implements interfaces(实现的接口)——此类所实现的接口列表,用逗号分隔。
Startup code(起始代码)——在模型中所有的对象都构造,连接,和初始化完毕之后,在进行其他任何操作之前执行的JavaTM代码。在这里可以启动对象行为,例如状态图,线程,和定时器。不同对象执行起始代码的顺序并没有一个固定的规则。
37
Equations(方程式)——与此活动对象相联系的方程式。请查看第5章“方程式”以了解细节信息。
Additional class code(附加的类代码)——这里可以定义任意的成员变量,嵌套的类,常数,以及方法。这些代码被加入到类的定义中去。你可以在此对象内部任何地方访问这些类数据成员。这里的方法可以在此对象的一些活动中调用,例如,在定时器到时的时候,或者在状态图状态变化发生时。 导入包
如果你希望使用另一个包中的类,那么你需要使用import声明来导入这个包,或者在所使用的类的名称前面加上此包的名称作为前缀。 ► 在活动对象类中加入import声明
1. 在此活动对象类的代码窗口中,在Import(导入)段内输入JavaTM导入声
明语句。
► 在工程中的所有类中加入import声明
1. 在Project(工程)窗口中,点击你希望向其中导入包的工程。 2. 在Properties(属性)窗口的Code(代码)页中,在Import(applies to all classes)(导入(适用于所有类))段输入JavaTM 导入声明语句。 从代码中访问活动对象
非复数对象的被封装对象anObject可以直接通过其名称anObject来访问。AnyLogicTM的活动对象都是类ActiveObject的实例。请查询AnyLogicTM类参考手册(Class Reference)以了解ActiveObject类的属性和方法。 ► 查看AnyLogicTM类参考手册
1. 在主菜单中选择Help|Class Reference(帮助|类参考手册)。
2. 浏览器窗口即打开,并显示AnyLogicTM类参考手册(Class Reference)。 活动对象类的getOwner方法将返回其父活动对象,即封装了当前对象的对象;如果当前活动对象为根(root)对象,则返回null。这一方法将返回一个ActiveObject类型的对象,如有必要,你可以将它的类型转换为你所需要的特定的已知对象类型。
活动对象之间的继承
活动对象类都是JavaTM类,因此活动对象类之间可以有继承关系。任何用户定义的活动对象类都直接或间接地继承自预定义的类ActiveObject。类
38
ActiveObject有一些为所有活动对象类所共有的属性。请参考AnyLogic类参考手册以了解更多关于ActiveObject类的属性和方法的信息。
然而这里仍然需遵守一条规则。在一个活动对象类和它的超类中,应有且只应有一个活动对象类是由AnyLogicTM生成的,而其他所有的类都应手动定义,例如,在外部文件中定义。 ► 为一个活动对象类设置基类
1. 在Project(工程)窗口中点击此活动对象类。
2. 在Properties(属性)窗口中,在Base class(基类)编辑框中指定此基
类的名称。 图17是一个活动对象类之间继承的实例。由AnyLogicTM生成的类——即,有结构图的类——都用显示在方框中。
TM
图17. 活动对象类之间的继承
39
2. 复数对象
AnyLogicTM支持对象复制(replication)——一种十分简单方便的建模方法,用于建模具有规则组织结构的任意大小和任意拓扑结构的对象,例如数组(vector),网格(mesh),圆环面(torus),超立方体(hypercube),链(chain),环(ring),等等。手动创建指定数量的对象并在他们之间建立连接关系十分繁重且有局限性,AnyLogicTM使你免除了这样的单调工作,并且能够形成具有预定义的常数数目对象的系统。
在AnyLogicTM中,你只需简单地声明一个复数对象,然后将此复数对象中的实例数目指定为参数。一个复数对象代表了一组属于同一类的活动对象。对象复制提供了十分简便的表示具有复杂结构和任意相互关系的对象的方法。
对象复制使你能够:
通过创建元素数目由模型参数指定的复数对象,从而构建大小可调节的系统。
通过AnyLogicTM用户界面或程序,在被复制的对象之间建立任意的相互连接,从而创建对象的复杂结构。
通过在运行时向复数对象组中加入或移除对象,来建模具有动态变化结构的系统。
请不要将对象复制与模型复制相混淆。模型复制只是单次的模型运行,而与对象复制无关。
创建一个复数对象
在AnyLogicTM中,你可以通过创建复数一个对象来创建一组具有相同类型的对象。首先,封装一个你希望从其创建结构的对象,然后将它声明为复数。 ► 声明一个复数对象
1. 在结构图中,点击你希望复制的被封装对象。
2. 在Properties(属性)窗口的Replication(复制)页面中,在Number of objects(对象的数目)编辑框中指定复数对象中所包含的单个元素的数目(复制因子)。 3. 复数对象的名称在结构图中显示时将在末尾加上一个星号。
你可以指定任何其值类型为integer或double的表达式作为被封装对象的数目。这样,你可以参数化复数对象中的对象实例的数目。你需要这样做的原因可能
40
是为了方便修改若干个复数对象中包含的对象数目。请参考第3章“参数”以了解关于参数的更多信息。
如果你使用参数作为被封装对象的复制因子,AnyLogicTM将创建数目为此参数初始值的对象实例。然而,如果你在运行时改变了此参数的值,AnyLogicTM并不会自动调整对象实例的数目。如果你需要能够在运行时调整实例数目,你应使用处理函数onChange_myParam()来进行创建和销毁对象实例(请参考下一节以了解如何在模型运行时对复数对象进行更改)。
在运行时访问和修改复数对象
这一节描述了在运行时如何从代码中访问复数对象的各个元素,如何向复数对象中添加对象,以及如何从复数对象中移除对象。请参考第节“手动创建和销毁被封装的对象”以了解关于在运行时创建和销毁被封装的对象的一般信息。
从代码中访问复数对象
你可以通过调用()来得到复数对象anObject中的活动对象数目。
为访问数组复数对象anObject中的任一单个元素,你需要使用方法(index),这一方法接受对象在此数组中的索引值作为参数,索引值范围从0开始到()-1。
你可以通过调用方法getIndex()来获得复数对象中的某一个元素的索引值。
向复数对象中加入/从复数对象中移除对象
为向复数对象中加入一个新的对象,你可以使用AnyLogicTM生成的方法
setup_ 下面的代码将对象obj加入到MyObject类的复数对象myObject1中去: 如果在结构图中存在到其他对象的连接,则对此新对象也将建立这些连接。 你可以使用dispose_ 下面的代码将删除复数对象myObject1中的最后一个元素: 41 ActiveObject的相关方法 final void setReplication(int index)——框架方法。你可以调用这一方法以将复数对象的一个元素放置于由参数index指定的位置。 连接复数对象 AnyLogicTM为你提供了一个方便的创建具有复杂拓扑的对象结构的机制。它支持在复数对象的各个元素之间,以及复数对象与其他对象(也可能为复数对象)建立任意类型的相互连接。 当你使用连接器连接两个复数对象的端口或变量时(图形连接器在第节“建立对象之间的相互作用”中有描述),你即可得到如图18所示的结构,即,数组client中的每个元素都与对象server相连。 图18. 复数对象之间的连接 然而,你仍然可以在复数对象之间建立任意类型的相互连接。细节信息在节“连接复数对象的各个元素”中给出。 42 连接复数对象与其他对象 一个复数对象代表一组对象的拷贝。当你图形化地在某个被封装对象的接口元素与复数对象的一个接口元素之间建立连接时,被封装对象的接口元素即被连接到复数对象中所包含的所有对象的接口元素上(请参考图18)。在某些情况下,你可能希望只将此对象的一个接口元素连接到复数对象中的某个对象个体上面。在AnyLogicTM中,你可以通过调整连接器属性来建立任意类型的连接。 ► 设置一个复数对象与另一个对象的接口元素之间的连接的类型 1. 在结构图中,选择连接器,连接复数对象的接口元素与另一个对象的接口 元素。 2. 在Properties(属性)窗口中,在Connect from interface element of(从…的接口元素连接)下拉选单中选择将此复数对象中的哪一个或哪些对象的接口元素连接到另一个对象上: 3. All objects(所有对象)——默认值。复数对象中所有对象的接口元素都 将连接到另一个对象的界面元素上。 4. First of objects(第一个对象)——只有复数对象中的第一个对象的接 口元素将被连接到另一个对象上。 5. Lat of objects(最后一个对象)——只有复数对象中的最后一个对象的 接口元素将被连接到另一个对象上。 图19示意说明了这些连接类型。 43 图19 你也可以连接两个复数对象的接口元素。默认情况下,一个复数对象内部所有对象拷贝的接口元素将连接到另一个复数对象的所有对象拷贝的接口元素上(如图18)。 然而,你也可以只连接其中的某些对象拷贝。这种情况下你需要指定复数对象中你希望连接的对象拷贝。在连接器的Connect from interface element of(从…的接口元素开始连接) 和To interface element of(连接到…的接口元素)属性中可以对此进行设置,方法与上面连接一个复数对象与一个被封装对象的方法相同。 图20示意了一些连接两个复数对象的接口元素的可能的例子。 44 图20. 复数对象连接示例 如果两个复数对象具有相同的元素对象数目,那么你可以指定一个复数对象的第i个对象拷贝与另一个复数对象的第i个对象拷贝之间建立连接,具体操作为在二者的下拉列表中都选择objects(i)——请参阅图20中的情况c。 连接复数对象中的各个元素 你可以在一个复数对象中的各个对象拷贝之间建立任意的连接关系。你可以连接复数对象中的某些元素对象的相同或不同的接口元素。由于对变量和端口的连接规则相同,因此我们下面将对复数对象的接口元素进行一般性的介绍。 ► 连接一个复数对象的各个元素对象 45 1. 在结构图中,连接所需的此复数对象的接口元素。你可以将一个接口元素 连接到它自身。 2. 在结构图中选择所创建的连接器。 3. 在Properties(属性)窗口中,在Connect from interface element of(从…的接口元素开始连接) 和To interface element of(连接到…的接口元素)下拉列表中指定你希望为每个被连接的接口元素连接的元素对象。 4. 选择All objects(所有对象),First of objects(第一个对象),或 last of objects(最后一个对象)以对复数对象objects分别连接所有元素对象,只连接第一个元素对象,或只连接最后一个元素对象。 5. 你可以在双方的下拉列表中都选择objects(i),以连接在被复制对象数组 中位于同一位置的对象拷贝的接口元素。你也可以在一个下拉列表中选择objects(i),在另一个列表中选择objects(i+1),以连接位置相邻的对象拷贝的接口元素。 图21中显示了一些连接的实例。 图21. 复数对象的对象数组中的一般性连接 46 使用程序连接复数对象 有时候你需要创建一个由对象组成的具有复杂拓扑的结构,这一结构如此复杂以至于无法通过图形的方法建立。或者你需要使用动态变化的连接来建模一个系统。这时你可以使用connect()方法和disconnect()方法来在运行时在复数对象以及它们内部的各个元素对象之间建立连接。 你可以使用Port或variableRef类的connect()/disconnect方法来连接/取消连接两个对象的端口或变量。这一方法接受两个参数:两个端口对象,或者两个变量对象。端口对象的名称即是此端口在结构图中的名称。然而,变量对象的名称是此变量在结构图中的名称加上前缀_ref_。 使用代码, ,或者 以连接两个端口。 使用代码VariableRef..connect, ,或者 以连接两个变量。 若需了解更多关于连接端口和变量的信息,请参考第节“在运行时连接端口”和第节“在运行时连接变量”。为了解更多关于Port和VariableRef类的信息,请参考AnyLogicTM类参考手册。 创建一个由单元组成的环 假定你想要建立一个由单元组成的环。 创建复数对象Ring,其中的元素对象数目由参数numberOfCells定义,此参数类型为integer。然后将output端口与input端口连接起来,并且定义如图21(例1)所示的相互连接。 手动连接最左边和最右边的对象,以形成一个圆环。在活动对象类Ring的代码窗口的Additional class code(附加的类代码)段输入onCreate()方法,以在对象创建时连接端口。 所得到的结构如图22所示。 47 图22. 单元组成的环 创建一个由单元组成的环面 假定你希望建立一个由单元构成的环面。设N为此环面的基数。那么你首先要声明N*N个被复制的单元。 图23. 构成环面的一个单元 现在你需要将相邻的被复制对象的相反界面元素连接起来,即将上面与下面相连,左上与右下相连,右与左相连,右下与左上相连。 你可以在类System的Additional class code(附加的类代码)段使用 onCreate()方法(这一方法在活动对象创建时将调用)来手动地连接各个单元: 这里方法index()将二维索引映射到一位索引,即: 48 结果形成的被封装对象组成的结构如图24所示。 图24. 由单元组成的模式 这里展示的技术使你能够创建由对象组成的的具有任意大小和任意拓扑结构的周期组织起来的结构。 在运行时查看和修改复数对象 你可以在运行时通过程序(请查看第节“在代码中访问复数对象”)或借助AnyLogicTM用户界面来访问和修改复数对象及其各个元素对象,方法与访问其他任何活动对象一样。 在模型浏览器中,一个复数对象在模型树中显示为树的一枝,其中包含各个元素对象(如图25)。复数对象的元素数目将随着此复数对象的名称一并显示。复数对象machine的元素对象命名为machine-0,machine-1,等等。你可以通过点击对应的加号或减号图标来打开或折叠对象内容。 49 图25. 模型浏览器中的复数对象 与其他活动对象一样,你也可以查看一个复数对象的结构和各个元素对象的当前状态:打开一个对象的结构图动画窗口,打开对象元素的查看和日志窗口,等等。运行和调试模型将在第10章“运行和观察模型”以及第13章“调试模型”中分别介绍。 如果你动态地向被复制对象数组中加入或从被复制对象数组中移除对象,则这些改变将自动显示于模型浏览器中。 动画显示一个复数对象 AnyLogicTM动画根据活动对象的动画而创建,并且将根据模型等级结构来进行组织。 你可以在容器对象的动画中显示一个复数对象的动画,显示 复数对象中所有元素对象的动画,或者 仅仅某些元素对象的动画。 为动画显示一个复数对象,你需要为复数对象类定义一个动画,并且将它放置于容器对象的动画中。这一动画绘制为一个矩形,其中显示复数对象中所有元素对象动画的内容,或只显示其中部分元素对象动画的内容。在动画编辑器中,你可以移动,缩放,和旋转一个被封装的动画形体;你也可以加入一些表达式表征某些所需的属性,以允许模型在运行时移动,缩放,和旋转被封装的动画形体。关于动画显示被封装对象的细节信息将在第中“动画显示等级模型”中给出。 如果在你创建复数对象类的实例时,被封装类的动画已经定义好,则被封装的动画形体将自动显示于容器对象的动画中。 50 如果你创建了一个复数对象,且尚未为此复数对象类定义动画,则被封装的动画形体未被创建。如果你在此后为被封装对象类定义动画,则你需要手动创建被封装的动画形体。 如果你希望在动画中只显示复数对象中的部分元素对象,那么你也需要在容器对象动画中手动放置被封装的动画形体。 为在容器的动画中放置复数对象的动画,你有两种选择: 为显示复数对象中的所有元素,你需要绘制一个被封装动画形体,且将其对应的被封装对象名称设置为整个对象数组,例如,cars,server。在这种情况下通常在复数对象类的动画的属性中指定不同的被封装动画的位置。 为只显示复数对象中选中的部分元素,你需要绘制所需数目的被封装动画形体,并且指定每个形体对应的被封装对象,格式为<被封装对象的名称>-<标号>,例如cars-5,server-0,等等。每个这样的被封装动画的位置通常直接在被封装动画形体的属性中指定。 ► 绘制复数对象的被封装动画 1. 点击Encapsulated Animation(被封装的动画)工具条按钮,或者 2. 在主菜单中选择Draw|Animation|Encapsulated Animation(绘制|动 画|被封装动画)。 3. 在容器对象的动画图中点击或拖动出一个矩形区域。 4. 在Properties(属性)窗口中,在Object(对象)编辑框中指定一个 被封装对象的名称(例如,cars),或一个特定的元素(例如,cars-1)作为这一形体所代表的对象。 5. 这样这一形体即显示所指定对象的动画内容。 如果被封装的对象被动态创建或销毁,则其对应的动画也将随着这个对象同步出现和消失。 51 3. 参数 活动对象可以拥有参数。通过使用参数,你可以在你的模型中参数化地表示活动对象。当对象实例都具有类中所描述的相同的行为,但仅仅行为的参数值不同时,则需要使用参数。 所有的参数在模型执行过程中都可见且可更改。这样,你可以在模型运行时通过改变参数来方便地调节你的模型。如果你需要,你也可以定义一个处理方法,以在参数发生变化时调用。 活动对象类的一个参数可以被关联到其封装的对象的参数上。在这种情况下,类参数的变化将传播到与之关联的对象参数那里。 变量(请参考第4章“变量”)和参数之间有一个明显的差别。一个变量代表模型的一个状态,并且可能在运行时改变。一个参数通常用来静态地对对象进行描述。一个参数通常在一次模型仿真中为一个恒定值,只在你需要调整你的模型行为时才发生变化。 如果你需要建模数据单元随时间的改变,请使用变量,而不要使用参数。 参数的类型 与其他仿真工具类似,AnyLogicTM也支持基本类型的参数:real,integer,boolean。但只有AnyLogicTM能在你参数化你的对象时给你无限的可能性,这通过支持JavaTM类类型的参数来实现。 你可以定义普通JavaTM类类型的参数,例如,一个String类类型的参数,用于代表字符串,或一个Vector类类型的参数,用于创建一个代表动态对象数组的参数。你可以创建一个Object类(所有JavaTM类的基类)类型的参数,然后将任意一个JavaTM类的实例赋给这个参数作为值。稍后你将需要检查此参数的真实类型,并且显式地将它转化为真实的JavaTM类类型。为了解关于JavaTM类的详细信息,请查看JavaTM SDK文档。 你可以在活动对象类代码中定义你自己的类类型的参数。 由于所有的AnyLogicTM对象都是JavaTM类的实例,因此你可以定义这些类类型的参数,从而使用AnyLogicTM对象作为参数。表1列出了一些AnyLogicTM对象以及其对应类的名称。 对象 Matrix(矩阵) 类 Matrix 描述 请参考第节,“矩阵”。Matrix类型的变量通常自动初始化为0,但Matrix类型的参数则需要你自己初始化。 52 Enumeration(枚Enumeration 请查看第节“枚举” 举) Hyper-array(超HyperArray 请查看第节“超矩阵” 矩阵) Lookup table LookupTable 查找表用于定义不能由标准函数的组合来描述function(查找的复杂变量依赖关系,例如,时间表。请查看表函数) 第节“查找表” 表1. AnyLogicTM参数类型 定义参数 你可以在在Parameter(参数)对话框中定义活动对象类的参数。 ► 向活动对象类加入参数 1. 在Project(参数)窗口中,点击此活动对象类。 2. 在Properties(属性)窗口中,点击New Parameter(新建参数)按钮 。 3. 此时即出现Parameter(参数)对话框(如图26所示)。 4. 在Parameter(参数)对话框中,设置如下参数属性: 53 图26. Parameter(参数)对话框 你可以在Parameter(参数)对话框中设置参数的如下属性: Name(名称)——此参数的名称。 Type(类型)——此参数的类型。 Default value(默认值)——参数的默认值。如果有预定义的符号,则这些符号将显示于组合框中。 Simple(简单)——如果设置了此属性,则此参数不是global(全局)或dynamic(动态)类型。 Dynamic(动态)——如果设置了此属性,则此参数为动态。请查看第节“动态参数”以了解关于动态参数的信息。 Global(全局)——如果设置了此属性,则这一参数为全局。活动对象类的全局参数在此模型中对于此类的所有实例都有相同的值。 54 Separator(分割符)——如果设置了,则这一参数用作分隔符。这样的参数在被封装对象的Parameters(参数)表格中显示为真实参数中间的空白行。分隔符用于可视化地分隔不同的参数组。 Predefined symbols(预定义的符号)——在Symbol Value(符号值)表格中定义的一组预定义符号,其中Symbol为预定义的符号的名称,Value为此符号的值。这样你就可以定义一些有用的常数,并且在指定参数的默认值或实际值时引用这些常数。 Hide if(隐藏条件)——定义一个条件列表,指定被封装对象的真实参数被隐藏的条件。你需要在这里指定Parameter(参数),==或!=比较运算符,以及Value(值)。 Description(描述)——对此参数的描述 在你完成了定义参数之后,新的行即显示于活动对象属性的Parameters(参数)表格中。 稍后,你可以使用Parameter(参数)对话框来更改参数的属性。 ► 更改参数属性 1. 在Project(工程)窗口中,点击活动对象类。 2. 在Properties(属性)窗口中,在Parameters(参数)表格中选择此参 数。 3. 在Parameters(参数)表格中,双击此参数,或者 4. 点击Edit(编辑)按钮 。 5. 此时即显示Parameter(参数)对话框。 ► 删除一个参数 1. 在Project(工程)窗口中,点击活动对象类。 2. 在Properties(属性)窗口中,在Parameters(参数)表格中选择此参 数。 3. 点击Delete(删除)按钮 ► 将一个参数向上移动 1. 在Project(工程)窗口中,点击此活动对象类。 2. 在Properties(属性)窗口,在Parameters(参数)表格中选择此参数。 3. 点击Move up(向上移动)按钮 ► 将一个参数向下移动 。 。 55 1. 在Project(工程)窗口中,点击此活动对象类。 2. 在Properties(属性)窗口,在Parameters(参数)表格中选择此参数。 3. 点击Move down(向下移动)按钮 ► 复制一个参数 1. 在Project(工程)窗口中,点击此活动对象类。 2. 在Properties(属性)窗口,在Parameters(参数)表格中选择此参数。 3. 点击Duplicate(复制)按钮 。 。 设置参数的真实值 一个活动对象类有一组形式参数。当对象被封装在其他对象内部时,真实参数值即可被赋值给此对象的形式参数;否则,则使用默认值。这样,你可以为同一个活动对象类的不同实例设置不同的真实参数值。 ► 为一个对象实例设置真实参数值 1. 在结构图中选择被封装的对象。 2. 在Properties(属性)窗口中,在Parameters(参数)表格的Value(值)单元格中指定参数值(如图27所示)。 3. 变更后的参数值用黑体显示以示强调。 图27. 被封装对象的属性页。Parameters(参数)表格 56 如果你在创建了活动对象类的实例之后再改变活动对象类的参数,请在进行操作之后检查所创建的实例中的参数。 你可以为实验的根对象的参数设置真实参数值。这样,你就可以创建若干个具有同一个根对象设置,但具有不同参数的实验。通过使用不同的当前实验对你的模型进行仿真,你可以观察和比较具有不同参数的模型的行为。 ► 设置实验根对象的真实参数值 1. 在Project(工程)窗口中,点击此实验。 2. 在Properties(属性)窗口中,在Parameters(参数)表格的Value(值)单元格中指定参数的值。 3. 改动之后的参数值将以黑体显示以示强调。 在运行时修改参数 你可以在运行时通过程序,或在AnyLogicTM查看器用户界面中,或在 AnyLogicTM动画中对参数进行修改。如果参数被关联到某个被封装对象的参数上,则此改动将沿着参数依赖关系进行传播,请参考节“参数传播”。你可以定义一个处理函数,此函数在参数发生变化时即被调用。 在模型浏览器中修改参数 ► 修改一个参数 1. 在模型浏览器(Model Explorer)中,双击此参数,或者 2. 右键点击此参数,然后在弹出菜单中选择Modify(修改)。 3. 此时即显示Modify(修改)对话框。 4. 在Enter new value(输入新的值)编辑框中输入新的值。 5. 点击OK。 在AnyLogicTM动画中修改参数 AnyLogicTM提供了一组控件(按钮,文本输入,复选框,滑块等),用于创建可交互的动画。你可以将活动对象的参数与一个动画控件相关联,在运行时改变控件,以此来修改参数的值。 你可以进行如下关联: 将boolean类型的参数与按钮或选框关联 57 将String类型的参数与编辑框关联 将double类型的编辑框与滑块关联 ► 将参数与动画控件关联 1. 在动画图中选择此控件。 2. 在Properties(属性)窗口中,从Variable name(变量名称)下拉 列表中选择此参数。 3. 如有必要,在Event handling code(事件处理代码)编辑框中指定用 户改变控件时所需执行的代码。 通过程序访问和修改参数 你可以通过程序修改一个参数。活动对象的一个参数myParam可以简单地作为一个成员变量myParam来进行访问。参数可以出现在活动对象内部的方程式和代码中。 然而,如果你在对参数进行修改,并且希望这一修改可以沿着参数依赖链进行传播(请参考地节“参数传播”),那么你需要调用方法——例如,由AnyLogicTM生成的set_myParam(),将你希望设置的值作为此方法的参数。 你可以从命令行设定根对象的参数,请参考地节“从命令行运行模型”。 被封装对象的参数在此对象由new运算符创建之后即被传递到此对象中。在构造函数执行过程中,参数尚未初始化。因此,如果你希望使用参数来初始化,例如,对象的一个成员变量,那么你无法在成员变量声明中完成此操作。你应在别的地方完成这一操作;例如,在此对象的onCreate()方法中。当onCreate()方法被调用时,其所有参数就已经完成初始化了。 参数传播 你可以将活动对象类的一个参数与此类封装的对象的一个参数相关联。在这种情况下,如果你在模型执行时改变了类的参数,则依赖于此参数的相关联的对象参数也发生改变。对于从修改点起沿着活动对象树往下的所有参数依赖关系,这一论断都成立。 你可以在如下情况下沿着对象等级结构向下传播参数值: 你需要改变若干个被封装对象(可能属于不同的类)的参数的值的情形。为此,你只需通过创建root对象的单个参数,然后将其值传播给若干个你需要改变值的参数。 58 你需要通过更改一个非根对象的参数来对模型进行优化的情形。在这种情况下,你也需要使用参数传播,这样你可以只改变根对象的参数就对模型进行优化。 你只能在相同类型的变量之间建立关联。 手动设置参数传播 ► 手动设置参数传播 1. 在结构图中选择被封装的对象。 2. 在Properties(属性)窗口中,在Parameters(参数)表格中选择你希望 与父对象参数关联的参数。 3. 在Value(值)域,输入你希望传播其值的父类参数的名称。 使用Export Parameter to Owner(导出参数到所有者)对话框设置参数传播 你也可以使用Export Parameter to Owner(导出参数到所有者)对话框设置参数传播 ► 设置传播链接 1. 选择被封装的对象。 2. 在Properties(属性)窗口中,在Parameters(参数)表格中右键点击包 含你希望传播其值的参数的行。 3. 在弹出菜单中选择Export to Owner(导出到所有者)。 4. 此时即显示Export Parameter to Owner(导出参数到所有者)对话框。 5. 如果你希望将对象参数与新的类参数进行关联,请选择Create a new parameter(创建一个新参数)选项,点击Next(下一步)按钮,然后在Parameter(参数)编辑框中指定参数的名称。 6. 否则,如果你希望将对象参数与已有的类参数相关联,请选择Select an existing parameter(选择一个现有参数)选项,点击Next(下一步)按钮,然后在参数表格中点击选取你希望传播的父类参数。 7. 点击Finish(完成)按钮。 移除一个传播链接 ► 移除一个传播链接 1. 选择被封装的对象。 59 2. 在Properties(属性)窗口中,在Parameters(参数)表格中右键点击包 含被链接的参数的行。 3. 在弹出菜单中点击Reset to Default(复位到默认值)。 变量的变化只在一个方向上传播,即在活动对象树中沿着参数依赖链向下传播。 图28示例了参数传播的过程 图28 对象objectB被封装在类ObjectA中。它的参数paramB被与父类的paramA参数相关联。 当你改变了封装类的参数paramA之后,被封装类的参数paramB即也发生改变。但改变参数paramB并不会影响参数paramA。 60 动态参数 动态参数是一种特殊类型的参数。动态参数的值在每次你访问此参数时将重新计算;即,这一参数类似于一个函数。 你可以输入其值的类型为此参数类型的表达式作为动态参数的值。例如一个boolean类型的表达式: 这里msg是活动对象类的预定义的变量,或JavaTM变量。通过提供不同的代码,你可以为每个活动类实例分别判断哪一个包裹更大。 请注意参数表达式在每次你访问此参数值时都将重新计算值。你可以使用函数调用来获得此参数的值——例如,myParameter(),而不是myParameter——这是由于动态参数在所生成的JavaTM代码中将变成函数。 通过使用动态参数,你可以通过一些代码将活动对象实例参数化,从而极大地提高了你的活动对象类的灵活性和可重用性。 61 4. 变量 一个活动对象中可以包含变量(variables)。变量通常用于存储模型仿真的结果,或者用于建模对象的一些随时间变化的特性和参数。在模型执行过程中,你可从AnyLogicTM用户界面中观察和更改变量。 变量的类型可以为任意的标量,具有任意维度大小的矩阵或超矩阵——由实数构成的一个多维数组。这一章只介绍标量类型的变量。AnyLogicTM矩阵和超矩阵将在第6章“矩阵和超矩阵”中详细介绍。 你可以定义一组微分方程,代数方程,以及公式,以描述变量随时间的连续变化。这样你就可以定义对象的连续时间行为。通过在运行时修改变量,你就可以对模型的行为进行调整。请查看第5章“方程式”,以了解如何定义方程。 变量可以被暴露到活动对象的接口上,并且与其他活动对象共享。在这种情况下,变量的变化被立刻传播到另一个对象上依赖于此对象的对象上。这样就定义了连续和/或离散时间的对象行为。 你可以在活动对象类的Additional class code段声明一个JavaTM成员变量。如果你只需要在活动对象内部,且只在离散的时刻访问一个数据项(即,既不与其他对象共享,亦不会连续变化),且你不需要在模型执行时观察或改变此数据项,则请使用成员变量,而不是变量。 如果你只需要建模对象的只在特定时刻(例如,在模型运行间隔)发生变化的静态参数,请使用参数(参考第3章,“参数”),而不要使用变量。 定义一个变量 变量可以为内部变量(或状态变量)或者公有变量(或接口变量)。状态变量只有在此活动对象内部才可以访问。而接口变量可以与其他活动对象共享。 如果你需要建立连续时间的对象相互作用,请声明接口变量,并且将它与其他的对象共享。其他情况下,如果你只需要在活动对象内部建模一些数据单元,请声明一个状态变量。 ► 定义一个状态变量 1. 点击Variable(变量)工具条按钮 ,或者 2. 在主菜单中选择Draw|Structure|Variable(绘制|结构|变量)。 3. 在结构图中,点击此类边框内部的一个位置。 4. 此时即出现一个新的变量,显示为一个小圆圈,如图29所示。 62 图29. 状态变量 ► 定义一个接口变量 1. 点击Variable(变量)工具条按钮 ,或者 2. 在主菜单中选择Draw|Structure|Variable(绘制|结构|变量)。 3. 在结构图中,点击此类的边框。 4. 此时即出现一个新的变量,显示为一个小三角形,如图30所示。 图30. 接口变量 将变量放置于类边框之上,则此变量即成为接口变量。 你可以方便地更改所创建的变量的可访问性。 ► 将一个变量作为接口变量 1. 在结构图中,将此变量拖动到类的边界上。 ► 将一个变量作为状态变量 1. 在结构图中,将此变量拖动到类的边界内部。 接口变量在结构图中显示为三角形。接口变量可以为输入(其对应的三角形指向对象内部)或输出(其对应的三角形指向对象外部)。变量的“方向”在变量共 63 享时十分重要——输出变量的改变将被传播到对其有依靠关系的输入变量那里(请查看第节“变量共享”以了解关于变量共享机制的细节描述)。 在新的变量创建之后,你可以在结构图中此变量右边打开的文字编辑器中指定此变量的名称。 移动,复制,和删除变量 对于结构图中的所有变量,你可以实行一些共同的操作。你可以复制,移动,和删除变量以及其他类元素。首先,你应点击此变量以将其选中。 ► 移动一个变量 1. 使用鼠标拖动此变量,或者使用方向键。 ► 复制一个变量 1. 按住Ctrl键,并且用鼠标拖动此对象。 ► 删除一个对象 1. 点击Delete(删除)工具条按钮 ,或者 2. 在主菜单中选择Edit|Delete(编辑|删除),或者 3. 右键点击此变量,然后在弹出菜单中选择Delete(删除),或者 4. 按Del键。 变量具有如下的属性: 属性 Name(名称)——变量的名称 Variable type(变量类型)——变量的类型。变量可以是任意类型的标量(Scalar),矩阵(Matrix),或超矩阵(Array)。 Direction(方向)——变量的方向可以为No direction|Input|Output(没有方向|输入|输出)。 Equation(方程式)——[可选]与此变量相关联的方程式。 Auto collect dataset(自动收集数据集)——如果设置了此属性,则AnyLogicTM将从仿真开始时即自动收集变量样本。否则,数据收集只在此变量被加入到一个图表窗口中时才开始。 Exclude from build(构建时排除)——如果设置了此属性,则此变量即被排除出此模型。 Show name(显示名称)——如果设置了此属性,则此变量的名称即显示于结构图中。 64 你可以声明任何Java标量类型的变量,即: 基本类型的变量(real,integer,boolean), 任何JavaTM类的实例(String,Vector,Object等), 你自己定义的类的实例,此类应定义于活动对象类代码中。 ► 定义一个标量类型的变量 1. 在结构图中选中此变量。 2. 转到Properties(属性)窗口的Variable type(变量类型)段。 3. 选中Scalar(标量)选项。 4. 在Scalar(标量)选项下方的组合框中指定此变量的类型。 TM 初始化一个变量 你可以为一个变量定义一个初始值。这一值在此后运行时可以更改(请查看第节,“在运行时查看和修改变量”)。 ► 初始化一个标量变量 1. 在结构图中选择此变量。 2. 转到Properties(属性)窗口中的Equation(方程式)段。 3. 在Form下拉列表中选择No equation。 4. 在Initial value(初始值)编辑框中指定此变量的初始值。 如果未指定初始值,则按照JavaTM规则对变量初始化,例如,一个double类型的变量即被设置为0。 如果为变量定义了公式,则其初始值由此公式计算得出。 由于输入变量的值通常依赖于与之连接的输出变量的值,因此你不能对输入变量的值进行初始化。 在运行时查看和修改变量 AnyLogicTM支持在模型仿真进行时对变量进行修改。你可以在运行时通过程序或者在AnyLogicTM查看器用户界面或者在AnyLogicTM动画中对变量进行修改。如果一个变量被关联到另一个变量上,则此修改将沿着依赖关系所示的方向传播,请查看第节“变量共享”。你可以定义一个处理函数,在变量值发生改变时调用此处理函数。 在模型查看器中修改变量 65 ► 修改变量 1. 在模型浏览器(Model Explorer)或结构图动画中双击此变量,或者 2. 在模型浏览器或结构图动画用右键点击此变量,然后在弹出菜单中选择 Modify(修改)。 3. 此时即显示Modify(修改)对话框。 4. 在Enter new value(输入新的值)编辑框中输入新的值。 5. 点击OK。 在模型查看器中,你只能修改基本类型的变量,即integer,real,boolean类型的变量。 查看变量 你可以在模型运行时从变量的查看窗口中观察变量的当前值。 ► 打开查看窗口 1. 在模型浏览器或结构图动画中用鼠标右键点击此变量,然后在弹出菜单中 选择Inspect。 2. 此时即显示此变量的查看窗口。 在AnyLogicTM模型动画中修改变量 AnyLogicTM提供了一套控件,用于创建可交互的动画。你可以通过将一个变量与一个动画控件相关联,然后在运行时对控件进行操作,来对变量进行修改。请查看第11章“动画”,以了解关于AnyLogicTM动画的信息。 你可以进行如下关联: 将boolean类型的变量与选框关联起来。 将String类型的变量与编辑框关联起来。 将double类型的变量与滑块关联起来。 ► 将一个变量与一个动画控件相关联 1. 在动画图中选择此控件。 2. 在Properties(属性)窗口,从Variable name(变量名称)下拉选 单中选择变量。 3. 如有必要,在Event handling code(事件处理代码)编辑框中指定在 用户更改此控件时所要执行的代码。 从代码中访问和修改变量 66 你可以将变量当作普通的Java对象,并且在离散时刻在任意表达式中对其进行修改,测试,和使用——例如在状态,转变,定时器的动作中,从线程中,等等。活动对象的变量var1可以简单地被当作成员变量var1来进行访问。 例如,输入如下代码以修改和检查变量varA的值: TM 使用图表显示变量的变化 你可以在模型仿真时使用AnyLogicTM图表窗口(请参考第节,“图表”)或使用特殊的动画控件——图表标记(请参考地节,“图表标记”),来可视化地显示变量的变化。图表标记把一个变量显示为如下形式之一:散点,甘特图,饼图,或者柱状图。 收集变量的历史信息 从仿真开始起,变量的样本即可以自动地被收集到。如果未设置自动收集数据,则数据收集只在变量被加入到图表窗口时开始。 ► 自动收集变量的历史信息 1. 在结构图中选择此变量。 2. 在Propertie(属性)窗口,选中Auto collect dataset(自动收集数据 集)选框。 你可以显示或导出数据集中的数据(请查看第17章,“收集数据和进行统计分析”)。 变量共享 活动对象之间可以共享变量。被共享的变量在任何时刻都将具有相同的值;即,一个变量的变化将立刻传播到另一个变量那里。这就为连续时间和离散时间的对象相互作用提供了条件。 只有具有兼容类型的变量间能相连接。 为建立变量共享,你需要将对应的对象关联起来(请查看第节,“建立对象关联”)。你可以进行如下关联: 在两个被封装对象的接口变量之间建立关联。 在一个容器对象的状态变量或接口变量与另一个被封装对象的接口变量之间建立关联。 67 如果你需要将一个容器对象中被封装对象的变量与其相邻的容器对象共享,则你需要将被封装对象的变量与此容器变量的一个接口变量相关联。其他情况下,如果你只希望将被封装对象的变量与封装此对象的容器对象共享,请使用状态变量。 你不可以在同一个对象的两个变量之间建立关联。 变量共享规则 被关联起来的两个变量通常其中一个作为依赖变量,其值依赖于另一个变量的值。在这个关联中,变量的角色由连接变量的方向决定。如上面所述,接口变量都具有显式指定的连接类型:输入,或输出类型。输出类型的变量的值的变化将传播到与其连接的输入类型的变量。 接口变量的依赖方向在此变量的属性窗口中指定。 ► 更改接口变量的依赖方向 1. 在结构图中选择此变量。 2. 在Properties(属性)窗口中,在Direction(方向)下拉选单中指定此 依赖关系的方向。 内部变量之间不具有显式的依赖关系。内部变量的角色取决于特定的连接情形。 AnyLogic允许一些定义良好的变量关联配置,以避免冲突。图31显示了正确的配置的情形。通用的法则是,在连接两个被封装对象的变量时,一个变量总是作为输出,另一个变量总是输入;在连接一个被封装对象的变量与一个容器对象的变量时,两个变量都应是同一个方向的。 TM 图31 变量的连接 68 变量的变化将根据定义好的一系列规则进行传播(在图31中,变量传播的方向用箭头显示)。 当两个被封装对象的变量被关联起来时,输出变量的改变将传播到输入变量。 当被封装对象和容器对象的变量被关联起来时,变量变化传播的方向取决于被封装对象的变量依赖方向类型: 当它为输出变量时,这一变量的改变将从被封装对象传播到其外部的容器对象上的被关联变量上。 否则,如果这一变量为输入变量,则变量的改变将从容器对象传播到被封装的对象。 AnyLogicTM允许将若干个依赖变量关联到同一个输出变量上。但是为了避免冲 TM 突,每个依赖变量上只能有一个输出变量与之相连;否则,AnyLogic即产生一个编译错误。图32显示了一些可能的不正确的关联配置。 图32. 不正确的变量关联情形 69 建立变量关联 你可以使用连接器通过图形的手段在变量之间建立关联(请查看第节,“活动对象之间的相互作用”以了解关于连接器的信息),或通过程序在变量之间建立关联。 使用图形化的手段在变量之间建立关联 可以在结构图中通过图形的手段在变量之间建立关联。 在被封装对象的变量之间建立关联 你可以通过将关联其接口变量来在两个被封装对象之间建立连续时间的相互作用。你只可以将一个输出变量关联到一个输入变量上。输出变量的值将传递到被关联的输入变量那里。 ► 在被封装对象的变量之间建立关联 1. 拖动被封装对象的变量到另一个被封装对象的变量上,或者 2. 点击Connector(连接器)工具条按钮 二个变量,或者 ,点击第一个变量,然后点击第 3. 在主菜单中选择Draw|Structure|Connector(绘制|结构|连接器),点击 第一个变量,然后点击第二个变量。 4. 此时图中即出现连接两个变量的连接器(请参考图33)。 图33. 被关联起来的两个被封装对象的变量 在被封装对象的变量与容器对象的变量之间建立关联 为在被封装对象的变量与容器活动对象之间建立连续时间的相互作用,你应将在被封装对象的一个变量与其父对象的一个变量之间建立关联。 如果你需要与父对象的相邻对象进行相互作用,则你需要将被封装对象的变量与父对象的接口对象进行关联。如果你只需要在容器变量和被封装对象之间进行变量值的传播,则请使用状态变量。 70 ► 在被封装对象的变量与容器对象的变量之间建立关联 1. 拖动被封装对象的变量到容器变量的对象上面,或者 2. 点击Connector(连接器)工具条按钮 二个变量,或者 ,点击第一个变量,然后点击第 3. 在主菜单中选择Draw|Structure|Connector(绘制|结构|连接器),点击 第一个变量,然后点击第二个变量。 4. 此时图中即出现连接两个变量的连接器(如图34所示)。 图34. 被关联起来的容器对象的变量和被封装对象的变量 如果结构图中的连接器显示为红色,则表明你建立了一个不正确的关联(请查看第节,“变量共享规则”,以了解关于关联的规则)。 向父活动对象导出变量 被封装对象的变量可以被导出到其父对象类中。这即表示此变量被加入到父对象类中,并且连接到被封装对象的被导出变量上(请参考图34)。这样被封装对象与其父对象即可以通过传播对象的变化来进行相互作用。 ► 将被封装对象的变量导出到父活动对象 在结构图中右键点击此变量,然后在弹出菜单中选择Export to parent(导出到父对象)。 在运行时进行变量关联 在运行时,变量可以通过使用VariableRef类的方法来进行关联和解除关联。使用connect()方法和map()方法,以进行变量关联;使用disconnect()方法和unmap()方法来解除变量关联。为了解关于VariableRef类的更多信息,请参考AnyLogicTM类参考手册。 这些方法接受被关联的变量对象作为参数。一个变量对象的名称即为此变量在结构图中的名称加上前缀_ref_。 71 使用connect()/disconnect()方法来为在等级树中位于同一层的对象建立或解除关联,其他情况则使用map()/unmap()方法。 也就是说,在以下情况下使用connect()/disconnect()方法来关联或解除关联: 关联两个被封装对象的变量 在以下情况使用map()/unmap()方法来关联或解除关联: 关联一个被封装对象的变量与一个容器对象的变量 使用connect()/disconnect()方法 图35显示了使用connect()/disconnect()方法的情形。 图35. 被封装对象的变量 调用connect()方法来在varA和varB之间建立关联。 调用disconnect()方法来以类似的方法解除对象之间的关联。 你可以在父活动对象类(在第一个例子中为ObjectC,第二个例子中为ObjectA)中任何地方插入此代码。 使用map()/unmap()方法 map()方法用于在位于不同层次的变量之间建立关联,即在一个被封装对象与一个容器对象之间建立关联。变量可以通过调用unmap()方法来解除关联。 72 图36. 一个接口变量和一个被封装对象的变量 图37. 一个状态变量和一个被封装对象的变量 图36和图37显示了map()/unmap()方法可以使用的情况。 为在这些变量之间建立关联,使用一个变量的map()方法,将另一个变量作为此方法的参数,在父活动对象类(ObjectA)的代码中任意位置加入如下语句: 为解除这些变量之间的关联,你可以调用unmap()方法: AnyLogicTM也为你提供了通过程序解除一个变量与其他所有变量的关联,以及检查输入变量是否被与输出变量关联起来的功能。VariableRef类中相关的的方法在下面列出。请参考AnyLogicTM类参考手册以了解细节信息。 VariableRef类的相关方法 Void breakLines()——解除一个变量与所有与之关联的变量之间的关联关系。 Boolean hasInputConnection()——如果输入变量具有一个输入的关联,则返回true,否则返回false。 73 改变变量,并对其变化进行处理 你也可以指定一个Boolean表达式作为转变的触发器,从而连续地对变量进行测试。只要此表达式的值为true(即使是在一个时间步的中间),则转变就变为允许。 我们推荐你指定等待状态作为触发器,而不是作为保护信号。这是由于保护信号的值在时间步中间将不会被测试。 在图38所示的例子中,对象myObj2的转变在对象myObj1改变了便变量x的值之后立刻触发。 图38. 对变量的变化作出反应 在上面的例子中,两个对象都是离散的。在下面将要展示的例子中,一个对象的连续行为将影响另一个变量的离散行为。myObj2对象的转变将在myObj1的变量x的值超过5时发生。 74 图39. 对变量的变化作出反应 如果一个变量在一组微分方程或代数方程中被使用,则变量之间的关联关系表明这些变量将被方程求解器当作一个变量。考虑下面这个例子。假定我们的变量之间的关联关系如图40所示,且公式x=-y和v=w-2当前分别在对象myObj1和myObj2中起作用。 75 图40. 变量的方程 即有如下的代数方程组: 我们可以对它进行求解: 76 变量的值将设置为这些值,无论其初始值如何。 77 5. 方程式 你可以定义一组微分方程式,代数方程式,和公式,以描述变量随时间的连续变化。你可以将方程式(以下方程式和公式将统称为方程式)与以下对象进行关联: 一个活动对象 状态图的某一个状态 在任意给定的时刻,在模型中都存在一个全局的活跃方程组。此方程组由所有对象和所有状态图的所有当前起作用的方程式组成。与活动对象相关联的方程式在整个模型生命时间内都保持起作用。与状态图的状态相关联的方程式只在状态图处于此状态时起作用。一个状态图对此全局方程组的贡献并不只是当前简单状态的方程式,也包括它的所有容器状态。 AnyLogicTM支持在方程式中使用基本数据类型,以及矩阵,超矩阵,请参考第6章,“矩阵和超矩阵”。 方程式的类型 一个方程式可以为以下三种类型之一: 微分方程(请查看第节,“微分方程”) 代数方程(请查看第节,“代数方程”) 公式(请查看第节,“公式”) 微分方程 微分方程定义为如下形式: 其中x为输出变量或状态变量,类型为double或矩阵类型,F(x, y, t, …)是一个代数表达式,其中可能包含此活动对象的任一变量,符号t表示时间。表达式F(x, y, t, …)中可以包含任意的代数运算或方法调用,例如,sin(),cos(),sqrt(),等等,或调用你自己的方法。 F(x, y, t, …)中不应调用间接使用活动对象的变量的方法;这些方法应将变量作为参数。确保此条件成立的最佳方法是只使用静态方法 F(x, y, t, …)中永远都不应调用对活动对象的变量进行更改的方法。 F(x, y, t, …)中不应包含任何条件运算符,例如,b>0 78 c:d。 你可以定义任意数目的微分方程。如果一个变量在此方程组中出现于等号左边次数超过一次,则为错误。输入变量不允许出现于等号左边。 例 在图41所示的例子中,变量x的行为由微分方程d(x)/dt = t定义。 图41. 微分方程 如果你用解析的方法求解此方程,你即得到x(t) = t^2/2 + C;如果你考虑初始值为x(0) = 1,则此式可化为x(t) = t^2/2 + 1。这是一条抛物线。图42显 TM 示了计算出的此条抛物线,并由AnyLogic对其进行绘制。 79 图42. AnyLogic所绘制的抛物线 例 图43所示的微分方程定义了一个数学摆;x是此数学摆的坐标,y是速度。由AnyLogicTM计算出的解显示于图44中。 TM 图43. 微分方程 80 图44. 数学摆的坐标和速度 代数方程 代数方程定义为如下形式: 其中x为一个输出变量或状态变量,为double类型,或为矩阵类型;F(x, y, t, …)是一个定义明确的代数表达式。为了解适用于F(x, y, t, …)的规则,请参考第节“微分方程”。 你也可以定义未知变量组,以保证位置变量的数目与代数方程式的数目相同。 你可以定义任意数目的代数方程式。不允许将输入变量作为未知变量。 例 图45显示了一个由两个方程组成的方程组,其中有两个未知变量。 81 图45. 代数方程 显然,解为x = -1,y = -1。 公式 公式定义为如下形式: 其中x为输出变量或状态变量,类型为double或数组/矩阵类型,F(y, t, …)是一个定义明确的算术表达式。为了解F(y, t, …)所应遵循的规则,请参考节,“微分方程式”。唯一的额外的限制是,F(y, t, …)中不可以包含x,否则它就变成了一个代数方程,则需要以另一种形式进行定义。 你可以定义任意数目的公式。如果一个变量在一组方程式中出现于等号左侧的次数大于一次,则为错误。输入变量不允许出现于等号左侧。 公式定义了变量之间的直接依赖关系。公式是代数方程的一种特殊形式,但它不需要耗费时间的数值求解。因此我们推荐尽可能使用公式,以提高模型仿真性能。 定义一个方程式 你可以将方程式指定为字符串。为了方便起见,你可以在活动对象类的 Equations(方程式)代码段,或者变量的Equation(方程式)段对方程式进行定义。这两个地方是自同步的,即,如果你在一个地方加入或移除了一个方程式,则此方程式在另一个地方也将自动被加入或移除。在活动对象类的Equations(方程式)代码段,你可以指定所有类型的方程式。然而,在变量的属性中,你只能为此特定的变量定义微分方程和公式。 82 ► 在活动对象类代码中定义一个方程式 1. 在Properties(属性)窗口中,右键点击活动对象类的Code(代码)项 目,然后在弹出菜单中选择Open Code(打开代码),或者 2. 双击此活动对象类的Code(代码)项目。 3. 此时此活动对象类的代码窗口即打开,请参看图46。 4. 在Equations(代码)段输入此方程式。 图46. 活动对象类的代码窗口 ► 为变量定义一个微分方程 1. 在结构图中选中此变量。 2. 在Properties(属性)窗口的Equation(方程式)段,从Form下拉列表 中选择Integral or Stock。 3. 在d(variable)/dt = 编辑框中输入方程式的右半部分。 4. 在Initial value(初始值)编辑框中输入此变量的初始值。 ► 为变量定义一个公式 1. 在结构图中选中此变量。 2. 在Properties(属性)窗口的Equation(方程式)段,从Form下拉列表 中选择Formula(公式)。 83 3. 在variable =编辑框中输入此变量的公式。 AnyLogicTM允许你在你的模型中使用箭头显示由此产生的变量之间的依赖关系(如图47所示)。一个从变量A指向变量B的箭头即表示变量A在变量B的方程式中被引用。 ► 显示/隐藏变量之间的依赖关系 1. 点击Show/Hide Variable Dependencies(显示/隐藏变量依赖关系)工具 条按钮 ,或者 2. 在主菜单中选择Draw|Variable Dependencies(绘制|变量依赖关系)。 3. 如果显示了依赖关系,则这一工具条按钮显示为蓝色。 图47. 显示于结构图中的变量依赖关系 你也可以将方程式与状态图的某个特定状态(简单状态或复合状态)相关联。为此你需要在此状态的Equations(方程式)属性中定义此状态图状态的方程式。 ► 为一个状态图状态定义方程式 1. 在状态图中点击此状态。 2. 在Properties(属性)窗口中,在Equations(方程式)段输入方程。 函数 AnyLogicTM允许在方程式中使用自定义的函数,即: AnyLogicTM提供了一组预定义的函数——最常用的数学函数。 84 AnyLogic支持一种特殊类型的函数——查找表(lookup table)。查找表是一个定义为表格形式的连续函数。你可能需要使用查找表来定义一个复杂的无法用标准函数的组合来描述的非线性关系,或用来以连续的方式使用定义为表格函数的数据。 AnyLogicTM允许你定义用户函数。当在多个方程式中存在同样的函数组合使用时,就常常需要使用此功能。在这种情况下,你可以简单地只需一次定义一个函数,然后多次使用这个函数。如果你需要定义一个数学表达式,你可以定义数学函数(mathematical function);如果你需要编写某些计算算法,你可以定义一个算法函数(algorithmic function,一个用JavaTM编写的函数)。 TM 预定义的函数 AnyLogicTM提供了一组预定义的函数——最常使用的数学函数。你可以在方程式的右边和在初始值中使用预定义函数的任意组合。 表2列出了这些预定义函数。 预定义的函数 sin, cos, tan asin, acos, atan, atan2 pow, sqrt exp log abs min, max round, rint, floor, ceil random delay xidz,zidz 描述 三角函数 反三角函数 幂函数和平方根函数 指数函数 自然对数 绝对值 两个参数的最小值和最大值 将实数转化为整数 在[0, 1)区间均匀分布的随机数 时间偏移 除法函数 表2. 预定义的函数 AnyLogicTM中有两个有用的常数,你可以在你的方程式中使用这些常数。 常数 底 描述 常数e——自然对数和指数函数的85 常数π——圆周率 表3. 常数 上述常数和函数(除delay,xdiz,zidz之外)都定义于类中。因此你也可以使用你所习惯的Math.<函数名称> ()记号。你可以参考JavaTM文档:。 预定义的函数可以通过AnyLogicTM函数向导(请参考第节,“使用智能感应”)来加入到你所需的位置。 仿真时间 你可以在方程式中引用当前的仿真时间。输入符号t或调用函数getTime()以得到当前的仿真时间值。 时间偏移 Delay函数实现了时间的偏移。 下面是一个简单的例子。变量y应是时间函数x偏移两个模型时间单位的结果。例如,令x代表指数衰减过程。我们为这些变量指定如下的公式: x = exp(-t) y = delay(x, 变量y即与变量x延时两个时间单元后相同。 图48. 时间偏移的例子 86 调用此函数的方法为: delay ( <变量>, <时间偏移值>, <初始值> ) 第一个参数应为一个AnyLogicTM变量,但不应是一个表达式。第二个参数应为常数或数值表达式(例如,函数调用)。这样,时间偏移值即随着仿真进行而改变。delay函数若具有0或负数的时间偏移值,则返回不发生偏移的原变量值。 使用智能感应 AnyLogicTM支持智能感应机制。这样,你就不再需要输入函数,变量,和参数的全名,从而显著地简化了方程的输入过程。你可以使用智能感应向导来插入一个变量名,或者插入对预定义函数的调用。 这一向导看起来类似于一个列表,其中包含有变量(图标为),参数(图标为),和函数(图标为),并且按照字母顺序排序(如图49)。你只需从列表中选择名称,对应的项目即被自动插入到表达式中。 ► 使用智能感应向导向方程式中插入一个对象名称 1. 在Equation(方程式)编辑框中,将鼠标移动到你希望放置此对象名称的 地方。 2. 点击 按钮,或者按Ctrl+Space。 3. 此时即出现智能感应向导,其中列出了所有模型变量和预定义函数。 87 图49. 智能感应函数向导 4. 滚动找到你希望添加的名称,或输入此名称的开头字母,直到它显示于列 表中。 5. 点击以选取此名称。此时向导即把被选定对象的细节信息描述显示于弹出 的文本框中。 6. 双击此名称以将这个对象插入到方程式表达式中。 查找表 有的时候你可能需要定义复杂的非线性关系,此关系无法使用标准函数的组合来描述。或者你可能需要在连续的模式中使用定义为表格函数形式的实验数据。这种情况下就需要对函数进行某种程度上的插值。 AnyLogicTM支持特殊类型的函数——查找表。查找表是一个定义为表格形式的函数。你只需通过对查找表中的数值进行内插和/或外插使数值连续起来。 你可以在方程式和其他函数中调用查找表函数(请查看第,“访问查找表数值”,以了解细节信息)。 ► 创建一个新的查找表 1. 点击New Lookup Table(新建查找表)工具条按钮 ,或者 2. 在主菜单中选择Insert|New Lookup Table(插入|新查找表)。 3. 此时即显示New lookup table(新建查找表)对话框。 4. 在此对话框中指定新的查找表的名称,选择将容纳这个查找表的活动对象 类,然后点击OK。 5. 你也可以在Project(工程)窗口中,右键点击将要包含此查找表的活动 对象类,然后在弹出菜单中选择New Lookup Table(新建查找表)。此时即显示New Lookup Table(新建查找表)对话框。 6. 在此对话框中指定新的查找表的名称,然后点击OK。 ► 定义一个查找表的数据 1. 在Properties(属性)窗口中,在General(常规)页面中点击Show Scatter…(显示散布)按钮。此时即显示Lookup Table(查找表)对话框(如图50所示)。 2. 在Data(数据)表格中输入数据点,即: 3. 在Argument(参数)单元格中输入参数的名称, 4. 在Function(函数)单元格中输入函数的值。 88 5. 在Interpolation/Approximation(插值/近似)段选择插值的类型。 6. 选择对超出范围的参数值所进行的处理。 图50. Lookup Table(查找表)对话框 Lookup Table(查找表)对话框中有如下几个控件: Scatter(散布)——此图标显示最终的查找表函数。 Add(加入)——点击这一按钮将加入新的数据点,其最后一个参数值递增。 Sort(排序)——点击这一按钮将对查找表中的数据点进行排序。实际上查找表中的数据点都自动按照参数值的递增顺序进行排序。 Del(删除)——点击这一按钮将删除在查找表中所选定的数据点。 Interpolation/Approximation(插值/近似)——指定查找表函数的插值方法类型(请参考第节,“函数插值”)。 If argument is out of range(如果参数超出范围)——指定在参数值超出范围时函数将如何处理(请参考第节,“在不可行区域内的函数行为”)。 你可以在查找表的Properties(属性)窗口的General(常规)页面中访问此查找表中的数据。 89 函数插值 查找表函数可以被进行插值。表4列出了可能的插值类型。 插值类型 描述 Constant interpolation(常数插在两个数据点之间的函数值与在具值) 有较小参数值的那个数据点时的函数值相同 Linear interpolation(线性插值) 两个点用直线段相连接 Spline interpolation (样条插4次样条。这两个点将用4次多项值) 式样条线段进行连接。对每个点,其左、右侧线段的0阶、1阶、2阶导数都相同。在终点处的2阶导数为0。 Approximation(近似) 此函数为一个多项式函数,其阶数由你在右边的编辑框中指定,此多项式应使得近似的数据点的均方根偏差最小。 不采用插值 表4. 插值类型 如果你需要得到光滑的曲线,则样条插值为最佳选择。然而,与线性插值相比,样条插值需要更多的计算时间。因此,如果非连续函数也可以为你的模型所接受,则可以使用线性插值。 在不可行区域内的函数行为 如果查找表函数被进行了插值,则其可行区域即是此函数的定义域;否则,若不进行插值,则其可行区域只是所定义的点集。你需要对查找参数超出可行区域之外时函数的行为进行定义。因此,在Lookup Table(查找表)对话框的If argument is out of range(如果参数超出范围)段,选择表5所列出的选项之一。 函数行为 Raise error(产生错误) 描述 如果参数超出可行区域之外,则产生一个运行时错误,且显示一个对话框以报告此错误。 Discrete values(离散值) Use nearest valid argument(使对所有位于可行区域左侧(右侧)之外的参数,此函数将采用可行区域最用最邻近的正确参数) 左边(最右边)的正确参数作为参数值。 90 Extrapolate(外插) 此函数将根据所指定的插值方式类型外插到值域之外。 Extrapolate by repeating(周期将定义域作为一个周期,将原函数外插) 当作一个周期函数进行外插。 Return custom value(返回自定义如果参数位于可行区域之外,则查的值) 找表返回一个自定义的值,此值定义于此选项右侧的编辑框中。 表5. 在不可行区域中的函数行为 样条被使用线性函数进行外插。在左(右)侧,外插函数是一个从最左(最右)点出发的射线,并且在此起始点具有与此样条相同的一阶导数。具有线性插值的函数将使用与最外侧的线性段连续的射线进行外插。 访问查找表值 为访问指定参数值对应的查找表值,你可以使用类LookupTable中的相关方法(简单地通过名称来访问查找表)。请参考AnyLogicTM类参考手册以了解细节信息。 LookupTable类中的相关方法 double lookup( double x )——返回与输入参数对应的查找表值。 double getDouble( double x )——返回与输入参数对应的查找表值。 double getDouble( Object x )——返回与输入参数对应的查找表值。 Object getObject( double x )——返回与输入参数对应的查找表值。 Object getObject( Object x )——返回与输入参数对应的查找表值。 数学函数 如果在多个方程式中都有一个标准的函数组合,那么你可以使用数学函数来对此函数组合进行定义,只需进行一次定义,即可多次重复使用此函数组合。 ► 定义一个数学函数 1. 点击New Mathematical Function(新建数学函数)工具条按钮 ,或者 2. 在主菜单中选择Insert|New Mathematical Function…(插入|新数学函 数)。 3. 此时New Mathematical Function(新建数学函数)对话框即显示。 4. 指定新函数的名称,选择将容纳此函数的活动对象类,然后点击OK。 91 5. 你也可以在Project(工程)窗口中,右键点击将容纳此函数的活动对象 类,然后在弹出菜单中选择New Mathematical Function…(新数学函数)。 6. 此时New Mathematical Function(新建数学函数)对话框即显示。 7. 输入新的数学函数的名称,然后点击OK。 一个数学函数具有如下的属性: 属性 Name(名称)——此数学函数的名称。 Function type(函数类型)——函数返回值的类型。 Arguments(参数)——此函数的一组参数。每个参数都按如下形式进行声明:Type Name,其中Type(类型)是此参数的类型,Name(名称)是此参数的名称。函数的参数可以出现在表达式中。 Expression(表达式)——此函数的表达式。 Function wizard(函数向导)——按这一按钮将打开函数向导。 Static(静态)——如果设置了此属性,则此函数为静态函数。 Exclude from build(构建时排除)——如果设置了此属性,则此函数被从模型中排除出去。 适用于数学函数表达式的规则与适用于微分方程表达式的规则类似(请参考第节,“微分方程”)。你可以使用模型时间符号,预定义的函数,查找表,和非全局的参数。请注意在这里你不可以使用变量。 在数学函数中使用变量可能会引起错误。如果你在一个自定义的数学函数中隐藏了对变量B的引用,然后在方程A中调用此函数,则AnyLogicTM无法了解其中的依赖关系。在这种情况下,无法保证方程将正确地被求解。 如果你希望在函数中对变量B进行引用,请创建一个新的函数参数,然后在方程A中调用此函数时,将变量B作为参数传递给此函数。 在输入表达式时,你可以使用函数向导。函数向导显示了一个列表,其中列出了函数参数(图标为),预定义的函数,以及查找表。你可以简单的在此列表中选择对象名称,则对应的对象即自动被插入到表达式中。请参考第节,“使用智能感应”,以了解如何使用函数向导。 ► 打开函数向导 1. 在Project(工程)窗口中,点击此函数项目。 2. 在Properties(属性)窗口中,在Expression(表达式)中点击你希望放 置一个对象名称的位置。 92 3. 点击Function wizard(函数向导)按钮,或者 4. 按Ctrl+space键。 算法函数 算法函数的作用与数学函数类似,但它更加强大,并且允许你实现比单个数学表达式更复杂的函数,即一个计算算法。算法函数使用JavaTM编写,这样你就可以充分利用JavaTM语言的所有优点,例如条件执行(if-then-else),循环执行 (while,for),分支(switch),等等。算法函数通常用于你无法通过使用预定义函数的组合或查找表来实现你的函数的情况。 ► 定义一个算法函数 1. 点击New Algorithmic Function(新建算法函数)工具条按钮 ,或者 2. 在主菜单中选择Insert|New Algorithmic Function…(插入|新算法函 数)。 3. 此时即显示New Algorithmic Function(新建算法函数)对话框。 4. 指定新建的函数的名称,选择将容纳此函数的活动对象类,然后点击OK。 5. 你也可以在Project(工程)窗口中,右键点击将容纳此函数的活动对象 类,然后在弹出菜单中选择New Algorithmic Function…(新算法函数)。 6. 此时New Algorithmic Function(新建算法函数)对话框即显示。 7. 指定新建的函数的名称,然后点击OK。 一个算法函数具有如下的属性: 属性 Name(名称)——此算法函数的名称。 Function type(函数类型)——此函数的返回值类型。 Arguments(参数)——此函数的一组参数。每个参数都应按如下形式进行定义:Type Name,其中Type(类型)为此参数的类型,Name(名称)为此参数的名称。函数的参数可以出现于函数体中。 Function body(函数体)——函数体。 Function wizard(函数向导)——点击此按钮将打开函数向导。 Exclude from build(构建时排除)——如果设置了此属性,则此函数将被从此模型中排除。 93 函数体与方程式的表达式不同。在这里你不能对超矩阵或模型时间符号使用运算符。为输入函数体,你可以使用函数向导,在函数向导中提供了参数和预定义函数的名称,以及一些十分有用的JavaTM运算符(图标为)。 运算符 for() {}, while() {} if() {}, if() {} else {} traceln() 描述 循环运算符 条件运算符 打印输出运算符 表6. JavaTM语言运算符 代数循环 有时公式组成了一个代数循环。在图51所示的例子中,对象myObj1中的公式定义了x对y的依赖关系,对象myObj2中的公式定义了y对x的依赖关系。 94 图51. 代数循环 显然,这两个公式构成了一个包含有两个变量的代数方程组。然而,用户对此无须关心。AnyLogicTM自动地检测到代数循环,并且用必要的方程式替换这些公式。在我们的例子中,即: 解为:x = 1,y = -1。 代数循环也可能发生于两个变量的初始值互相指向对方的情形。例如,var1 TM 初始化var2,var2初始化var3,var3初始化var1。AnyLogic将使用一个代数方程系统来替换这些表达式,用数值解法求解此系统,然后使用所求得的解来初始化这些变量。 由等式引起的运行时错误 在时间步中间(在离散的事件步之间),模型引擎用数值解法求解全局的方程组。这一过程可能会引起三种类型的错误。 用户指定的表达式中的计算错误,例如,被0除,或者对负数值求平方根。 不正确创建的方程组,例如,一个变量在等号左手边出现了多余一次。 方程组无法使用给定的初始值进行求解。 在第三种错误的情况下,你应分析此代数方程组,以检查此方程组是否有解。如果有解,我们推荐你给解一个好的初始近似值。你应在此方程组被激活之前设置初始近似值;即,在包含这些方程的状态的进入动作中设置初始值。 数值方法 在模型启动时,方程式即被组合到主微分方程系统中。在仿真过程中,此微分方程系统(DES,differential equation system)将通过AnyLogicTM内建的数值解法进行求解。AnyLogicTM提供了丰富的数值解法,用于求解序数微分方程 (ODE,ordinal differential equation),代数-微分方程(DAE,algebraic-differential equation),或代数方程(NAE)。 默认情况下,数值求解器由AnyLogicTM在运行时自动选择。你可以在实验的属性窗口中的Additional(附加)页面中的Numerical methods(数值方法)段设置用于求解方程式的数值算法。 95 图52. 实验属性窗口的Additional(附加)页面,Numerical methods(数值 方法)段 Differential equations(微分方程)——求解普通微分方程的较好的方 法。默认情况下,选择automatic(自动)方法,这将为当前的方程 组选择最快的计算方法。 Algebraic equations(代数方程)——求解代数方程的较好的方法。默认 情况下,选择automatic(自动)方法,这将为当前的方程组选择最 快的计算方法。 Mixed equations(混合方程)——求解代数-微分方程的较好的方法。默 认情况下,选择automatic(自动)方法,这将为当前的方程组选择 最快的计算方法。 Absolute accuracy(绝对精度)——求解方程时所要求的绝对精度。在无 法使用相对精度的时候使用绝对精度——即,在值接近于0时使用绝对精度。 Relative accuracy(相对精度)——使用变积分步长的方法(例如, RK45,RK853,RADAU5)求解方程时所要求的相对精度。默认情况下将采用这种精度。 Time accuracy(时间精度)——在求解方程时为找到变化事件(切换点) 所需要的时间精度。 Fixed time step(固定时间步长)——使用固定积分步长的方法(例如, Euler,RK4)所对应的固定时间步长长度。 如果你未指定特定的求解器,则AnyLogicTM在运行时根据系统的行为自动选择数值求解器。例如,在求解微分方程时,即使用四阶-五阶Runge-Kutta法开始进 96 行积分。如果系统不具有弹性,则AnyLogic采用另一个求解器——RADAU5,此求解器专为非弹性微分方程系统设计。这两种方法都可以改变其积分步长以得到所要求的精确度。你可以设置使用具有固定步长的方法(Euler法,和四阶Runge-Kutta法),这些方法不如上面的两个方法精确,但能够更快地进行数值积分。然而,如果你需要得到精确的解,请使用Automatic(自动)求解器。 TM 97 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igat.cn 版权所有 赣ICP备2024042791号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务