首页 arena中文教程arena中文教程第5章

arena中文教程arena中文教程第5章

举报
开通vip

arena中文教程arena中文教程第5章第5章 详细作业建模 在第四章里展示了用“基本操作”面板里的模块可以创建的模型种类。这些模块都是一些相对高层而且容易使用的模块,但离建立足够详细的模型还有很长的距离。有时这些高层模块对读者们来说已经足够了。 但有时还不行。在建模获得一些经验、所建模型越来越大、越来越复杂、越来越详细时,可能会发现需要对较低层的、更详细的、或者与“基本操作”面板的模块所提供的对象不同的事物进行控制或者建模。Arena不会让你被迫接受这些固定的建模构件,也不会强迫你为考虑模型的各个方面而不得不学习一门编程语言或编程语法。相反地,它提供...

arena中文教程arena中文教程第5章
第5章 详细作业建模 在第四章里展示了用“基本操作”面板里的模块可以创建的模型种类。这些模块都是一些相对高层而且容易使用的模块,但离建立足够详细的模型还有很长的距离。有时这些高层模块对读者们来说已经足够了。 但有时还不行。在建模获得一些经验、所建模型越来越大、越来越复杂、越来越详细时,可能会发现需要对较低层的、更详细的、或者与“基本操作”面板的模块所提供的对象不同的事物进行控制或者建模。Arena不会让你被迫接受这些固定的建模构件,也不会强迫你为考虑模型的各个方面而不得不学习一门编程语言或编程语法。相反地,它提供了几个不同的建模层次,从而为建立一些特殊逻辑结构的模型提供了较大灵活性。一种好的办法就是从高层模块开始,它们能走到哪儿你就建到哪儿(可能自始至终就是一层)。当你需要比它们更高的灵活性时,就到更低、更详细的层次中去。这种结构允许你随意开发容易的高层建模结构,也允许你在需要的时候到低层建模。 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 的Arena提供了所有这些建模能力,你能熟练掌握它们的用法。 这一章探讨了一些(当然不是所有)在“高等操作”(Advanced Process)面板和“操作块”(Block)面板中包含的低层详细建模构件;后一种面板提供了最底层的建模逻辑,其中的模块与作为Arena基础的SIMAN仿真语言中的程序块一致。这里我们采用的例子是一个很复杂的汽车修理与维护车间的模型。我们也会谈到一点非平稳(时间相关)到达过程,模型调试,以及更高层的动画定制等重要问题。 5.1节中给出了这个系统的描述,5.2节讨论了如何用一些新的Arena建模概念对这个系统建模,5.3节描述了一些基本的建模策略,5.4节给出了模型逻辑,5.5节讨论了模型调试问题,5.6节给出了一些调整动画细节的方法,以得到一些非标准的效果。在5.7和5.8节,我们对模型进一步完美化,并提出了几种新的Arena建模概念。在5.9节,我们向你展示了如何修改原始模型,以创造出更精美的模型。本章于5.10节结束,我们在这一节中提出了一种完全不同的模型,库存系统,并借此机会展示了如何使用Arena最底层和最详细的建模层次,即包含了SIMAN仿真语言的“操作块”面板。 在读完本章后,你应该可以建立非常详细和复杂的模型,也可以探索出Arena建模的丰富而又深入的层次结构。 模型5-1:汽车维护与修理车间 位于某中等城市市区的大型汽车修理商,由于其维护与修理业务增长太快而使得当前的设施不足,因此决定要扩建其汽车维护与修理车间。由于当前所处的位置的限制,他们考虑在郊区再建一个有三个修理间的新车间。新建的车间不仅应能提供额外的维护与修理能力,而且应位于现有多数顾客的附近。为了能够对工作流进行更好的控制,由位于市区的车间对两个地方的工作进行安排,而且主要的修理工作也将继续在市区车间进行。 根据该 计划 项目进度计划表范例计划下载计划下载计划下载课程教学计划下载 ,允许顾客最多提前三个工作日在新的郊区车间打电话提出预约服务(在预约的当天不提供服务)。例如,在周三打电话预约的顾客可以在周四、周五或周一得到服务。如果无法为顾客在给定的后续三天时间安排服务的话,他们可以第二天再打一次电话,或者在市区预约要进行的工作。该汽车修理商具有顾客服务需求的大量数据,对这些数据的分析表明,顾客要求服务的呼入电话平均每天29次,全天都服从(平稳的)泊松过程(也就是说,呼入电话的时间间隔独立、且服从相同的指数分布)。对数据的分析还表明,55%的呼叫者希望在第二天得到服务,30%希望在第三天;剩下的15%希望在第四天。如果不能安排在其选择的某一天内提供服务的话,他们有90%的可能性希望安排在之后的一天。 大部分顾客(80%)会选择全天将车辆放在这里,而少数顾客(20%)愿意一直等到服务完成。如果顾客选择等待,他们将会给定一个近似的等待时间。这个等待时间等于预计的完成工作的服务时间(被称作预定时间(Book Time))再加上放宽因子(一个小时)。建立这个新车间的目标之一就是使顾客具有很高的满意度。因此,公司决定每天最多安排5个希望就地等待服务完成的顾客预约。 无论实际服务时间是多少,该汽车修理商都用一组标准的估计服务时间(Book Times)来计算服务成本。各类服务活动的预定时间可用一个带有位移和比例因子的β-分布来表示(44+90*BETA(2,3),单位为分钟,且截断取整)。实际的服务时间与预定时间(Book Times)有些不同,它服从伽马分布GAMM(Book Times/1.05,1.05)。 该汽车修理商想使新车间盈利,但不知道每天应该安排多少预约服务,现在的处理是基于每天所能安排的预定时间(Book Time)小时数的最大数量来进行的。这个值是基于三个修理间、每间每天可用的服务时间是8小时来计算的。因为实际服务时间往往与预定时间有所不同,所以最后确定每天可供安排的时间为24小时。 假定每周有五个工作日,每天工作八个小时,每个修理间每小时的成本估计为45美元(包括所有的资本和劳动)。对顾客按预定时间的每小时78美元收费。因为实际服务时间与预定时间有一定的不同,所以该汽车修理商希望在修理开始的当天完成已安排好的服务。为了补偿服务时间的差异,每一个修理间每天最多可以加班3个小时。但是,加班的成本是每车间每小时120美元。如果服务在这个时间内无法完成,顾客的车辆就会在修理间放置过夜,服务在第二天完成。如果发生此事,那么汽车修理商会为顾客提供一辆替代车,为每辆替代车每天将花费修理商35美元。如果修理商的负荷较大,导致某车在当天的预约服务不能开始,此时假设顾客将自己的车开回家,第二天再开过来,因而就不需要替代车辆了。 对该系统所关心的统计量有:每天的利润,每天的预定时间,每天的实际服务时间,每天的加班时间,以及每天安排就地等待服务的顾客中没能完成的作业数量。 5.2 新的建模特性 从仿真的观点来看,这个问题与我们在第三章和第四章所研究的非常不同。最明显的区别是这个系统是一种服务性质的企业,而前面的系统是面向制造业的。虽然SIMAN仿真语言最初的版本(Arena是以该仿真语言为基础的)是为制造业的应用而开发的,但是现在Arena的能力也应用到了服务系统的精确建模,包括快餐店、银行、保险公司、服务中心和很多其它的企业。尽管这些系统都有各自的一些特点,但是基本的建模需求很大程度上与制造系统相同。 现在,让我们看一下汽车车间,然后找出新的需求。随着工作的继续进行,会发现我们已有的建模结构还不足以完成如此详细的系统建模。 5.2.1 多路径决策 进行服务预约时,将它安排到合适的工作日,然后等待这一天的到来。为此,根据预约日的要求,我们需要将实体或预约送到该模型的五个不同的部分。 虽然我们可以通过用一系列的“决策”模块(Decide)实现它,但是模型会变得难看而且也没有必要。你也许仍然还不太清楚,其实在第四章前三个模型里用到的Decide模块中可以含有三个或者更多的分支。 5.2.2 集合 随着模型越来越复杂,经常会发现需要模拟实体到达一个位置或站时,需要从几个相似(但是不完全等同)对象中选择一个。 最常见的情况是从一组资源中选择可用的资源。假设有三个操作员:Shelley、Lynn和Charity。他们中的任何一个都可以完成需要的任务,这时,只要他们当前都是空闲的,则可以选择这三个中的任何一个。“集合”模块(Set)为实现这种功能性提供了基础。Arena的集合包含了一组相似对象,这些对象可以通过集合名称和相应的下标来引用。这些对象构成了集合,每个对象是集合的一个成员。特定集合的成员都必须是同种类型的对象,例如资源、队列、图形等等。根据建模需要,可以将几乎任何一种Arena的对象收集到一个集合之内。一个对象也可以出现在一个以上的集合之内。例如在操作员集合(Operators)中包括了Lynn,但她又能作为一个调整人员,因此,可能会定义一个被称为“调整”(Setup)的资源集合,其中包括Lynn和Doug(Doug不是一个操作员)。现在,如果需要一个操作员,就从名为Operators的集合中选取,如果需要调整人员,就从名为Setup的集合中选取。因为Lynn是同属于两个集合中的一个成员,所以可能会在任何一个情景下选择她。用户可以按需要任意选择集合的数目或集合间是否有重叠。 对修理中心来说,我们用集合来建立修理间模型、描述实体图形和预约队列。 5.2.3 变量与表达式 在很多模型中,可能会在多个不同的地方重复使用数据。例如,在一个模型中有几个地方可能需要生成来自相同分布的服务时间,并将它们输入到需要的模块中去。但是如果要在实验中更改这个分布的参数(或者分布本身),就必须打开每一个包括该服务时间的对话框来改变参数值。有时,我们可能需要跟踪系统中实体总数变化的情形。还有的时候,我们可能在整个模型中需要使用很复杂的表达式,例如,可能根据零件类型来确定加工时间。Arena的“变量”(Variable)和“表达式”(Expression)模块可以容易地实现这几种要求。 “变量”模块(Variable)允许用户定义自己的全局变量并赋初始值,而且还可以按照它们的名称加以引用。它们也可以被指定为一维或二维的数组。“表达式”模块(Expression) 允许用户定义各类表达式和它们所关联的值。与变量相似,表达式也可以在模型中以它们的名称引用,可以被指定为一维或二维的数组。虽然变量和表达式看起来很相似,但是它们具有不同的功能。 用户定义的变量可以存储一些能够在仿真运行期间重新赋值的量。例如,我们可以定义一个叫做Wait Time的变量(用以表示等待时间),其初始值为2,在需要使用该量的地方输入变量名即可。我们也可以定义一个叫做Number in System的变量(用以表示系统中的零件数),其初始值为0。每次新零件进入这个系统,就在这个变量上加1;每次一个零件退出系统就减1。对汽车车间来说,我们用一个名位Day的变量来跟踪这一周的当前日。我们还会用很多变量来控制如何获得预约,如何在运行结束时收集用于计算统计量的信息。 与此不同,用户定义的表达式不能存储数值,而是提供了一种将某个名称和特定的数学表达式关联起来的方式。当名称在模型中被引用时,相关的表达式就会被计算出来,并返回其数值。例如,表达式可被用来计算一些分布或复杂等式的值,而计算公式中又包含了实体的属性值或者系统变量值的当前值。如果在模型中数学表达式只用在一个位置,将它输入到相应的位置可能会更容易。但是,如果表达式被用在几个位置或者要用的表达式的形式依赖于实体的属性,那么用户定义表达式通常会更好。对汽车车间来说,我们会用Expression模块(在“高等操作”面板中)来定义所生成的预定时间、实际服务时间和预定需求的类型(等待还是离开)这些表达式。 变量和表达式有很多其它的用处,随着你们对Arena的进一步熟悉,这一点会越来越明显。 5.2.4 子模型 在开发庞大而复杂的模型时,通常将模型分割成小的模型是有好处的,这种小的模型被称为原模型的子模型(submodels),它们之间可能互相有交互,也可能没有。这会为建模与测试过程提供便利。例如,我们可以将汽车车间模型分割成五个明显的(我们认为它们很明显)子模型:生成预约呼叫、进行预约、服务活动、更新性能变量和控制逻辑。 Arena以子模型的形式提供了这种分解能力。这种特点允许将模型分成不同层次的视图,也即子模型,每一个都在屏幕上有自己完整的工作空间。你既可以一次观看一个子模型,也可以观看模型全景(也即顶层 (Top-Level) 模型)。每一个子模型都可以包括常规的模型窗口(例如“电子数据表格”模块、静态图形和动画元素)所支持的各种对象。子模型本身也可以包括更低层的子模型;可以无限地嵌套下去。子模型可以连接到其它的模块中去,也连接到其它的子模型中去,或者孤立地处于一个Arena模型中。 在顶层模型视图和每一个子模型视图中,为了在逻辑区和动画区的不同区域中提供容易的导航,可以建立带有相关热键的“命名视图”。工程工具栏的“导航”面板(Navigate)可显示出列有顶层模型、所有的子模型、以及它们所以命名视图的树状结构。点击一个命名视图的或子模型视图即可显示该模型所在的区域,这使得在视图内和视图间的导航变得非常容易。 虽然以上汽车车间模型还不像很多实际模型那么大,也没有那么复杂,但是我们仍然用子模型来组织流程,并阐明概念。 5.2.5 实体副本 在开始更复杂的建模时,通常会发现创建“实体复本”的必要性。这些实体通常被用作控制实体,可以完成许多功能。这种用法的一个很好的例子将在9.3节介绍,在那里会讲到实体的受阻离开和中途退出等现象。也有的时候需要在模型的某处将一批实体集合成一个实体(也即将零件装盘),然后在模型的另一处再将成批实体分成单个。本书将在9.4节加以说明。在汽车车间模型里,我们需要创建实体副本,让它代表要求预约的来电。可使用“基本操作”面板中的“分离”模块(Separate)来创建或克隆实体的副本。 5.2.6 保持实体 模型中有时需要将实体保持在某个位置,直到系统允许这些实体行进的特定情况发生为止。我们已经看到其中的一种形式 ( 实体在排队等待资源空闲。但在此我们考虑更一般的情况,实体被保持的位置是由模型中其它地方的活动所决定的,如系统时间或系统条件。Arena提供了两种不同的保持实体的方法。第一种方法是实体被保持到由另一个实体发出行进信号为止;第二种方法是实体被保持到某些系统条件出现为止。在汽车车间模型中我们将采用第一种方法,可通过使用“保持”模块(Hold)和“信号”模块(Signal)来实现,也即将顾客的预约一直保持到安排对他进行服务的那一天为止。第二种方法将在9.4节介绍。 5.2.7 统计量和动画 我们需要的统计量也是比较平常的,与前面模型中收集到的没有很大不同。但是,系统的类型和分析需求却截然不同。先看一下分析需求。在分析服务系统时常见的目标是利润最大化或顾客满意度最大化,还有成本最小化(当然,从极端意义上讲,它们是相互矛盾的目标)。该汽车修理车间顾客满意度的关键测度的是在所承诺的完成服务时间以外的等待服务的顾客数。很明显,我们的目标就是使其最小化。影响这些测度的关键因素是各天所安排的等待服务的最大顾客数。创建模型后,我们可以很容易地增加或减小这个数,并确定其对性能指标的影响。我们需要认真考虑仿真要运行多长时间,以及所要建立的系统的类型。下一节会涉及到这些。 分析和提高利润是一个更加困难的问题。预约是基于Book Time的,而各天所需要的实际服务时间可能有很大的不同。因此,我们如果想要控制模型变量以提高利润,那么就需要知道改变这些变量所造成的影响。通常的仿真输出总结报告是不会直接给出这个信息的。但是我们可以通过增加一些统计量来收集和提供所需信息,这不难做到。 查看动画运行应该是很有帮助的,就像在观测实际系统一样。遗憾的是,与以前的模型不同,一般很难为这种系统加上动画效果以使其展示出系统运行状况。我们可以用动画模拟预约的队列和资源,但是相应的动画却是非常跳跃的,而且也不能提供我们所需要的时间方面的信息。虽然经常也观看这类系统的动画,但是这些动画一般都是用来“展示”而不是进行分析的。不过既然已经提及,我们还是会在5.6节介绍如何给这种模型加上动画的。 5.2.8 终态仿真和稳态仿真 大部分(尽管不是所有的)仿真可以被分为终态仿真和稳态仿真两大类。这主要是仿真研究的意图或目的方面的问题,与模型内部的逻辑或架构没有多大关系。 终态仿真(terminating simulation)是模型规定了特定的开始和结束条件的仿真,这些条件是对实际系统需求的真实反映。正如它的名字所体现的,仿真会按照模型规定的特定规则或条件终止运行。例如,一个商店在上午9点开门,开门时店内没有顾客;在晚上9点关门,并继续服务到所有的顾客都离开。再看一个加工车间的例子,它则运行到生产出订单所规定的500个装配件为止。这一类型的关键是仿真有一个明确定义的(虽然在开始时可能是未知的)、自然的结束的时间,也有一个明确定义的启动方式。 与终态仿真不同,稳态仿真(steady-state simulation)则是通过长时间仿真运行来对某些性能指标加以估计的仿真形式;也就是说,理论上的仿真时间应该是无穷大。在原理上,这种仿真的初始条件是无关紧要的(虽然通常在实际中不是这样)。当然,稳态仿真也必须在某一个时间点停止,不过正如所想象的那样,仿真会运行很长时间,因此需要设法保证它运行的时间足够长。我们将在7.2节讨论这个问题。有关稳态仿真的例子也很多,例如一个儿科急诊室在实际中永远不会停止或重新开始,因此稳态仿真对此会很合适。有时候某些系统在实际中会有终止状态,但为了 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 其某种最坏的或者负荷最大的情况,仍可以采用稳态仿真模式进行。 现在为汽车修理车间模型选择应该用哪种仿真形式。虽然根据定义能看出终态系统和非终态系统的差别很明显,但在实际很少如此。一些系统刚开始时采用一种类型,但是更进一步检验后却发现它们实际上属于另外一种。再加上有些系统同时包括两种类型的因素,这就使得这一更加复杂了,此时往往依据分析人员所处理的问题的类型来确定仿真的分类。例如,考虑一个在上午11点开门,晚上11点关门的快餐店。如果对该快餐店的日常运作问题感兴趣,就可用非平稳泊松到达过程,并将系统看成是终态仿真进行分析。如果只对发生在午饭前后两个小时内的高峰期的运作感兴趣,则可以假设系统是一个以峰值到达率到达的平稳过程,并可将这个系统作为稳态系统进行分析。 乍一看,汽车修理车间很像是一个终态系统,这个系统似乎可以以空闲状态开始和终止。但也有可能某天不能完成所有的工作(记住我们只允许三个小时的加班)。需要在车间放过夜的车辆会对第二天的初始条件有很大影响,因此我们可以将系统考虑成稳态的。假如情况并非如此,我们将会继续在第六章将汽车车间问题作为终态系统进行分析。 5.3 建模方法 在第一章的图1-2中,简要讨论了Arena的层次结构。这种结构允许将任何层次的建模构建组合在一个仿真模型中。在第三章和第四章中,我们基本上都是利用“基本操作”面板中的构件来开发我们的模型,尽管在处理故障或其它特殊统计量时确实也用到了几种在“高等操作”面板里的数据模块。 在创建模型时,我们推荐一般情况下要尽可能维持在最高的层次上构建模型。但是,当发现这些高层构件已无法描述必要的细节时,你就应该将模型的某些部分移到下一层,而不能牺牲仿真模型的准确性。你可以将不同层次和面板中的的建模构件同一个模型中混合使用。随着对各种面板(和建模层次)的进一步熟悉,你会发现自己能够很自然地这么做。在继续建模工作进行之前,先简要讨论一下可用的面板。 “基本操作”面板(Basic Process)提供了最高层环境。使用该面板可以既迅速又容易地创建大部分系统的高层模型。“创建”模块(Create)、“操作”模块(Process)、“决策”模块(Decide)、“赋值”模块(Assign)、“ 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 ”模块(Record)、“分批”模块(Batch)、“分离”模块(Separate)和“清除”模块(Dispose)的综合运用可具有很大的灵活性。实际上,如果研究一下这些模块,就会发现有很多其他的特点我们还没有探讨。在很多情况下,仅单独使用这些模块就能提供仿真项目需要的所有细节。因为这些模块提供了几乎所有模型都需要用到的常见功能,因此不管所希望的建模细节处于哪一层,你都有可能用到以上模块。 “高等操作”面板(Advanced Process)提供了其他一些更详细的建模能力,补充了“基本操作”面板的功能。例如,“占用-延时-释放”模块(Seize-Delay-Release )的组合就提供了与Process模块基本相同的建模逻辑。“高等操作”面板中的模块的一个有用特点就是你可以将它们放在模型中几乎所需要的任意组合体中。实际上,很多有经验的建模人员都是从这一层开始,因为他们感觉由此建立的模型对用户来说会更明晰。 “高等运送”面板(Advanced Transfer)提供用于物料搬运活动方面的构件(如运送设备和传送设备)。与“高等操作”面板提供的一般的建模能力相似,“高等运送”面板中的模块在为物料搬运系统建模时也具有很高的灵活性。 “操作块”面板(Blocks)提供了更低层次的建模能力。实际上,它提供了用来创建“基本操作”面板、“高等操作”面板和“高等运送”面板中所有模块的基本功能。另外,它还提供了很多在高层模块中不能实现的其它特殊用途的建模构件。如“while”循环、概率和逻辑组合分支、以及自动搜索等特征。你可能注意到其中的几个模块与那三个高层面板中的模块有相同的名称。尽管名称一样,但模块却是不同的,能够通过颜色和形状来区分这两种模块。 如果你以前用过SIMAN仿真语言,并在其中分别定义过模型文件和实验框架(即使在Arena中你也可以这么定义),那么“操作块”面板和“基本操作”面板、“高等操作”面板以及“高等运送”面板之间的差别就很容易解释了。这些差别最好通过两类面板中的Assign模块来阐明。在使用“基本操作”面板的Assign模块时,你可以随意选择合适的赋值类型。如果给一个新的属性赋值,Arena会自动定义这个新的属性并将它加入到模型各处的“属性下拉列表”中。尽量在最高层建模的一个原因就是“操作块”面板中的模块没有这么方便,其中的Assign模块只能完成简单的赋值,不能定义新的属性。虽然有这样的缺点,但在“操作块”面板中的模块仍具有一些其它面板所不具备的强有力的特征。 另外,“构模元素”面板(Elements)中也有实验框架方面的模块。例如,在这里可以利用Attributes模块定义新属性。由于建模时可与更高层次面板中的模块相混合使用,所以实际中很少需要这些功能。但是如果某些特殊问题需要建立一个最低层的模型(如使用Visual Basic、C、和FORTRAN等程序设计语言的功能),则也可通过Arena接口加以调用。 “操作块”面板和“构模元素”面板也提供了为连续系统建模而设计的模块,这些内容将在第11章介绍。 现在让我们返回到汽车维修车间模型中,该模型确实要用到“基本操作”面板中的模块所不具备的特点。在开发模型时,我们会同时用到“基本操作”面板和“高等操作”面板中的模块(在本章的结尾,会用“操作块”面板和“构模元素”面板开发一个库存模型)。在一些情况下,确实需要用到较低层的构件;而在其它情况下,就只是展示一下它们的特性。在创建含有低层构件的模型时,开发模型的方式会稍有不同。 如果仅有较高层的构件,一般可对活动进行分组,然后再使用适当的模块加以建模。而如果含有较低层的构件,就需要对实际活动有细致的描述。从某种意义上说,你的模型要能成为刻画这些活动的详细的流程图。不过要做到这一点并不容易,除非你对各种模块的逻辑非常熟悉。 5.4 建模 在此,我们把模型分成几个部分,分别直接对各个部分进行开发,同时介绍各部分的功能。以下按顺序分别介绍七个部分: 5.4.1节:定义数据, 5.4.2节:创建子模型, 5.4.3节:生成预约呼叫, 5.4.4节:进行预约, 5.4.5节:服务活动, 5.4.6节:更新性能指标变量, 5.4.7节:控制逻辑。 数据一节包括建模所需要的数据模块,接下来一节会说明如何创建子模型,剩下的五部分每一个都将作为子模型加以开发。最后得出的顶层模型窗口外观上类似于图5-1。因为以后才给模型加上动画,所以我们这里先删除包含在模块中的所有动画对象。 P186 图5-1 模型5-1:汽车维修车间模型的顶层模型视图 当读完下面有关建模的七个部分后,你可能能感觉到,这是开发一个模型所遵循的基本步骤。理想情况下,人们总希望能够先对模型的结构有一个比较好的规划,以使其比较容易建立。但是在实际中,你会常常返回到先前完成的部分,不断对模块或数据加以增、删、及修改。因此在开发复杂模型时,一定不要指望能一次就成功(我们当然也不会)。 5.4.1 定义数据 让我们从Run>Setup菜单对话框开始。在Project Parameters表页中的Project Title栏内输入项目名称。在Replication Parameters表页中,我们随便设定为重复仿真运行10次,每次仿真20天。因为希望输出报告中的单位是小时,所以这里选择Hours作为基准时间单位(Base Time Unit)。 由于实际系统开始时都是空的(除非有车辆放过夜,以及在随后3天有预约), 因此可令预备运行时间的长度(Warm-up Period)为0。因为设定了多次重复仿真运行,所以需要告诉Arena在相邻两次重复仿真运行之间要做什么。有四种可能的选项。 选项1:初始化系统(是),初始化统计量(是) 这会进行10次统计上独立而且相同的重复仿真运行并生成相应的报告,每一次都是在时间0时开始且系统初始状态为空,每一次都运行240个小时。随机数发生器(见12.1节)在重复仿真运行之间连续产生独立同分布的(IID)随机数。在前一次仿真结束时可能需要放过夜的车辆在下一次重复仿真开始时将不被保留。 选项2:初始化系统(是),初始化统计量(否) 这会进行10次独立重复仿真运行,每一次都在时间为0时开始且系统初始状态为空,每一次都运行240个小时,但输出报告中的统计结果是各次累积的。因此,报告2会包括前两次重复仿真运行的统计结果,报告3会包括前三次重复仿真运行的统计结果等等。这里的随机数发生器的运行也象在选项1中一样。 选项3:初始化系统(否),初始化统计量(是) 这会进行10次仿真运行,第一次从时间0开始,第二次从240开始,第三次从480开始等等。因为系统在多次重复仿真运行之间没有进行初始化,所以时间会连续增加,任何放过夜的车辆都会被带到下一次重复仿真运行中。报告只包括单独一次重复仿真运行的统计量,而不是多次累积的结果。 选项4:初始化系统(否),初始化统计量(否) 这样也会进行10次仿真运行,第一次从时间为0开始,第二次从240开始,第三次是从480开始等等。因为系统在多次重复仿真运行之间没有初始化,所以时间将连续增加,任何放过夜的车辆都会被带到下一次重复仿真运行中。但这时输出报告中的结果是累积的。第10次报告的结果将与做一次时间为2400个小时的单次仿真运行是一样的。 理想情况下,我们不希望有很多车辆在修理间过夜,因而希望采用独立的重复仿真运行模式。这意味着要么选择选项1,要么选择选项2。此处将选择选项1(有关的详细情况见第6章)。 本例共有三项资源(三个修理间)。所有这三项资源都是可变容量的(在4.2节已作过讨论)。我们可以为每一种资源单独定义一个容量调度;但是由于它们的容量调度形式是一样的,所以可以简单地重复使用单个调度(尽管这么做会使你的模型在将来可能产生变化时减少了灵活性)。在建立这种容量调度时,可使用图示调度编辑器(Graphical Schedule Editor),在Options对话框中将time slots的个数设定为12,将图中y轴的maximum capacity设定为2(我们实际上可以设定它为1)。容量调度如图5-2所示。 你可能注意到,该容量调度要求这3个修理间每天有11小时可用,每天工作8小时,再加上可能有3个小时的加班。资源在每天的第一个小时都不能用,因为要用这一个小时来调度未来的预约,并允许当天的顾客在这个时候到达。 下一步就是定义资源。我们为容量调度类型选择“优先抢占”(Preempt)选项,因为车辆在标准的8小时工作和允许的3小时加班后有可能仍未完成服务。在这种情况下,将停止对该车辆上的工作,并选择在第二天完成该项工作。最后的电子数据表格视图如图5-3所示。 P188 图5-2 图示调度编辑器:修理间容量调度 定义完资源以后,就可以用“基本操作”面板中的“集合”模块(Set)来定义集合了。 利用Set模块可以定义资源集合、计数器集合、计数型统计量集合、实体类型集合以及实体图形集合,也可以利用“高等操作”面板中的“高等集合” 数据模块(Advanced Set)来定义其它的Arena对象集合。点击Set模块,然后在电子数据表格视图中双击相应位置以添加一个新的条目,这样就可以定义一个集合。我们会带你详细了解创建该集合的细节。在Name单元格中输入Bays,从Type单元格的下拉列表中选择Resource。接下来定义集合中的成员,点击Member栏的“0 Rows”按钮,打开包含所定义的各项资源的电子数据表格,然后双击相应位置打开一个新的空行。因为已经定义了资源,所以可以用下拉列表中选择每个成员的资源名称。已完成的Bays集合成员的电子数据表格视图如图5-4所示。 P188 图5-3 资源电子数据表格窗口 P189 图5-4 Bays集合成员的电子数据表格窗口 下面定义两个实体图形的集合,Customer(顾客)和Vehicles(车辆)。每一个集合都有两个成员,分别表示在等待的顾客和将车辆留下来的顾客。已完成的Set数据模块如图5-5所示。 P189 图5-5 Set模块的电子数据表格窗口 我们还需要创建一个队列集合以存放将来的预约。首先,需要用“基本操作”面板中的“队列”模块(Queue)定义五个队列(周一预约队列到周五预约队列)。然后,利用“高等操作”面板中的Advanced Set模块来定义队列集合。在Name单元格中输入Appointment Queues,从Type单元格的下拉式列表中选择Queue。然后在电子数据表格中输入五个队列成员的名称,类似于前面的资源集合。该集合的五个成员如图5-6所示。 P189 图5-6 高等集合模块成员的电子数据表格窗口 下一步,用“基本操作”面板中的“变量” 数据模块(Variable)来定义变量。应该指出的是我们没有必要一定利用这个模块定义变量。当你在所需的某处(例如Assign模块)定义一个新变量时,Arena会将这个新变量的信息自动输入到Variable数据模块中。但是,如果需要定义数组变量或所定义变量的初始值不为零,那么就必须要使用这个模块来设定所需要的数组大小或变量初始值。 本例将总共定义15个变量。前六个变量是用来控制模型的:保存当前日期的变量(Day),令其初值为4(后面再详加叙述);用来保存当天预约作业的预定时间(Book Time)当前值的数组变量(Day Load);预定时间小时数的最大值(Max Load),令其初值为24;等待服务完成的顾客数的最大允许值(Max Wait),令其初值为5;用来保存当天等待作业数的当前值的数组变量(Wait Load);以及每天打入电话要求预约的平均顾客数(Calls Per Day),令其初值为25。 下面三个变量(以及最后两个变量)将在仿真运行结束时用来计算累积输出值:到现在为止完成的预定时间小时数的总数(Day Book Time);到现在为止完成的实际服务时间小时数的总数(Day Actual Time);到现在为止完成的加班时间小时数的总数(Day Overtime);当前在修理间存放过夜的车辆的存放总天数(Total OT);被延期的等待作业的当前数量(Day Wait Late)。 中间的四个变量将被用于控制逻辑:仿真中当前工作日的序号(Work Day);当日的工作开始时间(Day Start Time);当日的正常工作(不包括加班)结束时间(Day End Time);用来决定等待作业是否被延期的宽放量(Wait Allowance),令其初值为1。最后的电子数据表格视图如图5-7所示。 P190 图5-7 变量定义的电子数据表格窗口 我们还需利用 “高等操作”面板中的“表达式” 数据模块(Expression)来输入模型所需的几个表达式,包括用于确定每个呼入顾客的预定时间的表达式,用于确定顾客是否想要等待自己的车辆的表达式,以及确定实际服务时间的表达式。这样就可以很容易地根据需要将这些分布直接输入到模型中去。 从上一段讨论的第一个表达式开始。打开Expression模块,在Name单元格为第一个表达式输入名称Book Time Expression,然后在Expression Values单元格输入AINT (44+90* BETA (2,3) ) /60。可以简单地将上式用键盘敲入,或者用“表达式构造器”为其输入。因为大部分汽车修理车间的预定时间都是以整数分钟表示的,所以我们用Arena中的表达式AINT截去小数部分,返回一个不大于且紧邻该数的整数(AINT函数是Arena的很多内置数学函数之一,这些函数完整的清单可以在帮助菜单中的“数学表达式”(Mathematical Expressions)主题下找到)。注意,我们将结果除以60,以把时间转化为小时。 第二个表达式(Wait Priority Expression)用来决定顾客是否会一直等到其服务完成。其表达式为DISC(0.20,1,1.0,2),它将会以0.2的概率返回1,以0.8的概率返回2。在这种情况下,1就意味着顾客会等到服务完成。 最后一个表达式与前面的表达式有关,因为它需要用到第一个表达式得出的值。在生成预定时间时,将它存储在一个叫做Book Time的实体属性中。随后将把Book Time属性值带入表达式Actual Service Time,用于生成实际服务时间,其表达式为GAMM(Book Time/1.05, 1.05)。 最终的数据项需要“高等操作”面板中的“统计”模块(Statistic)。其中所有的条目都是输出类型的(Output Type),这就意味着这些值只能在每次重复仿真运行结束时求取。前面三个条目以小时为单位计算每天服务所需的平均预定时间、平均实际服务时间和平均加班时间。利用前面定义的变量就可以计算这些值。第四个表达式是求取平均每天被延期的等待作业数量。 最后一个统计量由三项组成,用于计算平均每天的利润。第一项(Day Book Time / Work Day)*78,表示根据预定时间按每小时收费78美元计算的已完工工作的收入。第二项(Day Overtime / Work Day)*120,表示因加班而导致的成本。最后一项的前半部分(Total OT / Work Day)*35是由于需要为没能在预定时间内完成服务的顾客提供替代车辆而造成的损失,第二部分24*45是资金和人力成本。 这些表达式可以直接输入,也可以用“表达式构造器”输入。最终的电子数据表格视图如图5-8所示。 P192 图5-8 Statistic模块电子数据表格窗口 以上完成了所需的数据定义工作,现在可以建立模型逻辑了。 5.4.2 创建子模型 通过选择菜单Objects>Submodel>Add Submodel可创建子模型。此时鼠标指针将会变成十字形,将它移到你想放置子模型的那个模型窗口中,点击一下就可将其放好,如图5-9所示。这个子模型对象的名字是Submodel跟着1个数字,该数字随着子模型的添加而递增。 若要将子模型对象的名字按自己的要求定义,则鼠标右击该子模型,选择Properties项打开子模型属性窗口,如输入界面5-1所示。我们将第一个子模型命名为Generate Appointment Calls(生成预约呼叫)。新的子模型默认有一个进入点和一个离开点。对第一个子模型来说,将进入点数量改为0,因为这个特殊的子模型仅被用来利用Create模块为模型的其它部分生成呼叫。可以在Description栏输入对子模型的一些描述,不过由于这个模型很简单,仅用名字就描述得足够清楚了,所以此处就不输入更多的描述了。 按照以上过程创建剩下的四个子模型,使得最后的视图看起来如图5-1所示。在创建过程中,你可能需要注意该图中每一个子模型进入点和离开点的个数。一旦将所有子模型放在合适的位置,并赋予它们正确的属性,就可以开始构造模型逻辑了。若要打开子模型并添加或编辑模型逻辑,只需要双击子模型或者用“工程栏”中的的“导航”(Navigate)面板在子模型和顶层模型之间来回切换即可,如图5-10所示。若要关闭子模型窗口,你可以用Navigate切换,或在子模型窗口中的空白处右击鼠标,并选择Close Submodel即可。现在我们已经可以建立实际模型了。 P192 图5-9 新建的子模型 P193 输入界面5-1 子模型属性窗口 5.4.3 生成预约呼叫 这个子模型会生成每天的预约呼叫,并将它们传送到下一个预约处理的子模型。除了第一天以外,逻辑过程都是非常直观的。在子模型中将生成单个的实体(每12个小时一个),确定当天呼叫的次数,变量Day递增,创建足够多的实体副本使当天的离开实体数量等于呼叫的数量,最后为每一个离开的实体赋必要的属性值。 回忆一下,顾客只允许预约未来三个工作日中的某一天。因为我们假定没有预备仿真时间(Warm Up),所以我们应当认为在第一天仿真开始时已经有预约了。因此我们首先需要检查一下是否处在第一天。如果是的话,就创建三个实体副本当作将要处理的预约。因为Day变量初值为4(周四),所以它将被递增到5(周五),并且初始时相当于包含了三天的顾客预约呼叫(周一、周二或周三)。接下来会将变量Day重置为周一,并让初始实体生成预约呼叫。 P193 图5-10 Navigate面板 生成预约呼叫、并为变量和属性赋值的模块如图5-11所示。我们已经使用过这些模块类型中的大部分,其中两个新的模块,“延时”模块(Delay)和“分离”模块(Separate),分别来自“高等操作”面板和“基本操作”面板。 P194 图5-11 生成预约呼叫 该子模型的逻辑过程可以总结如下: p194 (程序代码) 第一个模块是Create,用以在每天的开始时创建实体,如输入界面5-2所示。在Name和Entity Type栏输入相应的名称和实体类型,常数12小时表示的到达间隔时间(每天的仿真时间长度),以及第一次创建实体的时间(第0.01小时)。剩余数据接受默认值。我们希望在建立了控制逻辑子模型后,再解释为什么在创建第一个实体时加入了微小的延迟,要不然等到那里时你可能就已经忘了这件事了! P195 输入界面5-2 Create模块 在第一个Assign模块中,对变量Day递增1,并令变量Call Number(呼叫数)的值为1,如输入界面5-3所示。 P195 输入界面 5-3 第一个Assign模块 然后,这个实体被送到名为Check for Startup的Decide模块,这个模块能使实体的运动按照某种可能性或条件而产生分支。分支的目的地是由图形连接定义的。到达实体将检查每一个所定义的分支选项,并前往满足条件的第一个分支的目的地。如果所有的指定条件都没满足,实体将会自动从模块底部的False离开点离开。 在此处的Decide模块中(如输入界面5-4所示),我们在Type处选择了2-Way by Condition选项,以检验当前是否处在仿真运行的开始时间,也即当前的仿真时间是否是小于1的。如果是,就将实体送到下面的Separate模块;否则,就将它送到为呼叫数量赋值的Assign模块。 P195 输入界面5-4 Decide模块 表5-1 Decide模块中的条件符号 描述 语法选项 描述 语法选项 与 .AND. 或 .OR. 大于 .GT. > 大于等于 .GE. >= 小于 .LT. < 小于等于 .LE. <= 等于 .EQ. = = 不等于 .NE. <> 一个条件可以是任何有效的表达式,但是典型情况下会包含一些比较运算。这些条件可以包括表5-1中的任何符号,以及逻辑表达式。 如果是处在仿真开始时刻,实体将被送到后面的Separate模块(在“基本操作”面板中),如输入界面5-5所示。Separate模块可以对到达实体进行复制,也可以将组合成批的实体分拆成为其初始的单个实体(更多内容详见9.4节)。在模型中,我们将创建三个实体复本,以生成仿真前三天的预约。要实现这一点,可在Type中选择Duplicate Original选项,在# of Duplicates栏输入3作为副本数量。注意,该模块有两个离开点,原先的实体将从上面的点离开,而三个实体复本将从下面的点离开。 现在跟着这三个实体复本,它们被送到后面的Assign模块,在这个模块中用泊松分布来生成呼叫数量(Number of Calls),泊松分布的均值储存在前面定义的变量Calls per Day中,如输入界面5-6所示。 P196 输入界面5-5 第一个Separate模块 P197 输入界面5-6 第二个Assign模块 然后,实体被送到第二个Decide模块,在这个模块里,检验变量Day的当前值有没有超过5,如输入界面5-7所示。这个变量保存了当前处于本周的第几个工作日,范围从1到6。在第一个Assign模块中曾对此变量增加了1,现在则需要检验它是否达到了6。 P197 输入界面5-7 第二个Decide模块 如果这个变量的当前值为6,那么该实体就被引导到随后的Assign模块中,在这里该变量会被重置为1,然后,这个实体被送到第二个Separate模块。如果前面的Decide模块的条件是False,那么实体将会绕过后面的Assign模块,被直接送到第二个Separate模块。 在最初的Create模块中创建的单个表示了这一天的所有呼叫。虽然在仿真运行开始时就对这个实体制作了副本,但是这个实体在目前仍然代表了一天所有的呼叫。我们用第二个Separate模块来复制剩下的呼叫。在这里只需要复制所需要的数量减1,因为初始实体将会被当作所有呼叫中的一个来看待,如输入界面5-8所示。 然后,这些实体被送到最后一个Assign模块,在该模块中要对一系列的属性赋值。Day Inc属性表示顾客希望进行预约服务的第一天(可在三天内进行预约服务)。对于在服务时选择等待的顾客来说,其Priority属性被赋值为1;而对愿意把车留在维修车间的顾客来说,其Priority属性被赋值为2(可用前面建立的Wait Priority Expression表达式来为Priority属性赋值)。期望服务时间被赋给Book Time属性。Try Day属性表示顾客愿意在当周进行预约服务的第一天(后面将检验此值是否大于5),其值为Day Inc属性值加上Day的当前值。最后,利用前面定义的图形集合为实体图形赋值,并将实体送到子模型的离开点。 P197 输入界面5-8 第二个Separate模块 5.4.4预约服务 随着对Arena的能力学得越来越多,开发的模型越来越复杂,你会发现在建模以前很有必要对模型的逻辑加以认真规划。否则,你可能会发现自己在不停地前后移动或删除那些被用错的模块。不管采取什么方法来规划模型,你都应该在模型变得非常复杂之前对它们加以认真思考。很多的建模者会用铅笔(自信的人则用钢笔)和纸,用相似的术语事先草拟出它们的逻辑过程。其他一些人则用更正式的方法,用标准流程图的符号建立一个逻辑图。还有一种方法就是构造一个将要进行的各种活动的顺序表(如前面一节)。这种方法有助于将建模的步骤 规范 编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载 化,降低错误的数量和修改模型的次数。随着对这种方法的进一步精通,你甚至可以直接使用Arena的模块来安排模型的基本逻辑(毕竟它们与流程图元素很相似)。但是,即便到了那种程度,我们仍然建议在安排好全部的模型逻辑之后再开始处理细节。 在一开始就建立一系列逻辑后,可能会很快发现它们过于复杂,以至于无法用一种简明的形式来描述,在建立复杂模型时并不罕见。所以我们还是先带你浏览完这个模型逻辑再进入细节。 在阅读对模型的描述时,可同时参阅一下图5-12。首先需要进行检验,以保证顾客想进行预约服务的日期是有效的(取值在1到5之间)。如果不是这样,就将它重置为有效日期。接下来再检验一下当前的预约队列,看看是否还有空位给顾客(根据Book Time来定)。如果还有的话,就检验它是不是一个等待作业。如果是,就增加那一天的等待工作数和Book Time的数量。这个实体被引导到子模型一个出口处,在那里将其放到相应的预约队列中。如果图中一系列条件都不成立,实体就被送到第二天再试的逻辑部分。如果要求预约服务的时间在三天内排不下,就删掉顾客的预约呼叫,记住只允许在未来三天进行预约服务。如果要求的时间已经在预约服务的界限上,就检验一下看顾客是否想在第二天再试试(90%的可能性是顾客愿意这样)。如果不是,就删掉这个预约呼叫。如果顾客想在第二天再试试,那么就增加变量Try Day的值,将实体送回逻辑过程的开始部分,重新再试。在浏览详细逻辑之前,注意一下这个子模型有一个进入点,五个离开点。 P199 图5-12 预约服务逻辑 现在,让我们重新开始浏览一下逻辑细节。回忆一下前面生成的一个值,它表示顾客希望安排自己的预约服务的第一天,这个值赋被给了Try Day属性。在第一个Decide模块中检验一下Try Day的值是否超过5。因为Day属性的当前取值范围是从1到5,而加入的增量取值为从1到3,所以Try Day可能得到从2到8的某个值。如果这个值是6到8(这些值表示下周的周一到周三),那么就需要减去5。在后面的Assign模块中就是这么做的。 得到了一个有效的Try Day值后,接下来就需要检验是否有空间安排顾客要求的预约服务。Book Time属性的值代表了这个顾客的期望服务时间。前面曾定义过一个数组变量Day Load,它是顾客要求服务的那天已安排的预约服务的Book Time小时数的总量。还定义过一个变量Max Load,这是在任何工作日内允许安排的Book Time小时数的最大值。可以用下面的表达式检查一下是否还有空间安排该顾客的服务。 Book Time + Day Load(Try Day)<= Max Load 如果这个表达式结果为真,则表示有空间安排,于是就将实体送到下一个Decide模块中去,在该模块检验顾客是否愿意等待服务。如果其Priority属性的值为1,那就表示这是一个愿意等待的顾客,则将实体送到下一个Decide模块中,在这个模块中检验安排在那天的等待顾客数是否满足条件。前面还曾定义过一个数组变量Wait Load,它表示预约在那天进行服务的等待顾客数的当前值。相应地还定义过一个变量Max Wait,它表示在任何一天可以安排的等待顾客数的最大值。可用下面的表达式看看是否还可以安排顾客的预约 Wait Load(Try Day)< Max Wait 如果还有空间,那么就在后面的Assign模块中将当天等待的顾客数加1。 在两种情况下可以安排预约:有可用的时间,并且该顾客可以不在此等待;或者有可用的时间,到达的是一个希望在此等待的顾客,并且有等待的位置。如果上面两个条件中的任何一个为真,就将该实体送到名为Assign Job的Assign模块,在这里将实体的Book Time值累加到Day Load变量中。 然后那个实体被送到最右面的Decide模块,在这里再根据预约日期将它送到合适的离开点,如输入界面5-9所示。在这个模块中,选择N-Way by Condition类型并输入五个条件,每个条件用以检验属性Try Day中的每一个有效值。然后,这个实体被引导到合适的分支(位于Decide模块的右下方),从这里将它送到那五个可能的离开点之一。我们将会在下一节讨论下一个子模型时再来看这些实体。 注意,只有在某个表达式值的为真时,实体才会从该表达式对应的离开点离开。还有一种可能就是这些表达式的值没有一个为真。当然,这也就意味着在模型中犯了一个错误。因此,我们增加一个名为Error的“清除”模块(Dispose),在此将所有条件均为False的实体送走。 P200 输入界面5-9 N-Way Decide模块 P201 输入界面5-10 第二个Decide模块 如果实体无法在Try Day时间进行预约服务的话,就会被送到到名为Stop Check?的Decide模块,以确定Try Day值是否已达到3,若是则表明不能再进行预约服务了。这时实体被送往名为No Appointment的Dispose模块加以清除(或许该顾客第二天会再打电话预约)。如果Try Day值为1或2,则实体被送往名为No Next Day Check? 的 Decide模块,如输入界面5-10所示。在这里选2-Way by Chance选项,并在Percent True栏输入10。当一个实体进入这个模块时,Arena会自动生成从0到1的随机数,如果这个随机数值小于或等于0.10(10%的可能性),实体会从模块的右边(标注为True的分支)离开;否则,它将从模块的底部(标注为False的分支)离开。 如果条件为真,实体就被送到与前面的Decide模块相连的同一个Dispose模块中。如果条件为假(90%的机会),实体就被送到随后的Assign模块中,对Day Inc和Try Day属性值递增1。然后实体将从这里被送回到最前面的Decide模块,并试图在下一个可用的工作日安排预约。 5.4.5 服务活动 服务活动子模型的逻辑很简单(如图5-13所示),因此没必要事先做更多的描述,边做边说即可。首先,注意到子模型有五个进入点。你可能在图5-1中已经注意到,前面子模型中的五个离开点是按照相同的顺序连接到这个子模块中去的。最高点对应的值为1,表示在周一预约服务,最低点对应的值为5,表示在周五预约服务。每一个进入点都连接到自己相应的“保持”(Hold)模块中,其名称分别为Monday List到Friday List。 P201 图5-13 服务活动逻辑 名为Monday List的Hold模块如输入界面5-11所示。Hold将实体保持在队列中,直到某个系统条件得到满足为止。在此处,实体被一直保持到接到一个值为1的信号为止。等到我们介绍控制逻辑子模型时,你将会看到将这个信号是从哪里发出来的。对Monday List模块来说,在Type栏选择Wait For Signal选项,并接受默认值1作为信号值。然后在Queue Name栏输入Monday Appointment Queue作为队列名称。你可能还记得在5.4.1节曾定义过五个队列,并将它们存放在一个高等集合中。这是模型中用到这些队列的第一个地方。 P202 输入界面5-11 Monday Hold模块 剩下的四个Hold模块只是在名字、信号值和队列名称上有所不同而已。这四个模块的信号值从2定义到5,对应于周二到周五的工作日。在每个周一工作日开始时,发出信号1以释放所有相应的实体(顾客的服务预约)进入后续模块。信号2则在周二的开始时发出,依此类推。 释放出来的实体被送到随后的Assign模块中,在这里利用Vehicle图形集合为实体赋一个新的图形,将当前的仿真时间赋值到实体的Arrive Time属性中。这些实体进入“占用”(Seize)模块(在“高等操作”面板中),如输入界面5-12所示。通常情况下,我们可以使用Process模块,但在这里,需要将Process模块中的的“占用”部分与“延时”部分分开(你马上就会发现这么做的原因)。在模块的Resource部分,选择Type为Set选项,并在Set name栏中输入Bays作为集合名称(前面曾定义过这个集合),在Selection Rule栏接受默认值Preferred Order,在Save Attribute栏中输入Bay Number。最后,在Queue Name栏中输入Bay Queue。 P203 输入界面5-12 Seize模块 现在,打开Queue数据模块(新名字Bay Queue是自动加上的),将Type选为Lowest Attribute Value选项,在Attribute Name中输入Priority。其结果是到达的实体将会进入Bay Queue,并根据它们的Priority属性值的大小加以排列。这意味着希望在此等待的顾客将被放在队列的前面,先于其他顾客接受服务。记住我们曾向这些顾客许诺尽量快地完成对他们的服务,使他们的等待时间能够最少。在Seize模块中选择Preferred Order选项,因为我们想按照它们在集合中列出的顺序(Bay 1,Bay 2,Bay 3)来占用修理间资源。等到在这一章后面要修饰模型时,就可以知道为什么要这么做了。 当实体被分配到修理间资源时,便被送到后面的Assign模块中,在此将当前的仿真时间赋给Start Time这个新属性。这个值是很有用的,因为我们借助它可以得到对实际服务时间的统计,而且在更新性能参数时也会用到它。 实体接着进入随后的“延时”(Delay)模块(在“高等操作”面板中),如输入界面5-13所示。在这里输入名称和前面定义好的表达式Actual Service Time Expression,并在Units处选择Hours选项作为时间单位。 P204 输入界面5-13 Delay模块 在延时完成以后,实体进入到“释放”(Release)模块(在“高等操作”面板中)中,如输入界面5-14所示。在模块的Resource部分,为Type选择Set选项,在Set Name中输入Bays,为Release rule选择Specific Member选项,在Set Index中输入Bay Number。基本上,此处释放的资源就是在前面的Seize模块中分配给该实体的资源。可通过追踪保存在Bay Number属性中的资源集合下标来确保所释放的资源是正确的。 这些实体接下来被引导到子模块的离开点。在此指出,Seize模块、Delay模块和Release模块的组合能产生与Process模块相同的功能。如果不需追踪服务开始的时间的话,则可以直接用Process模块。 P204 输入界面5-14 Release模块 5.4.6 更新性能指标变量 到达这个子模型的实体,表示已经接受完服务并且即将离开系统的顾客。回顾5.4.1节,我们定义了五个变量来说明系统的性能:Day Book Time,Day Actual Time,Day Overtime,Day OT和Day Wait Late。粗略一看,这个工作相当容易。但是,系统中可能存在一个或多个顾客还没有接受完服务的情况,这大大增加了这个操作的复杂性。本节涉及到的Arena模块如图5-14所示。 原书P205 图5-14 更新性能指标逻辑 到达的实体将直接被送到第一个Decide模块,用以判断这个顾客车辆是否在修理间放置过夜。在控制逻辑子模型中(这个模型将在下一节中加以讨论),我们将计算出用来表示每个工作日起始点的仿真时间(例如,1代表第1天,13代表第2天等),同时把这个值赋给变量Day Start Time;类似地,计算出每个工作日正常结束点的仿真时间(例如,9代表第1天,21代表第2天等),并且把这个值赋给变量Day End Time。通过比较属性Start Time和变量Day Start Time的值,我们可以确定这辆车是否曾放置过夜。我们运用下面的表达式进行比较 Start Time >= Day Start Time 如果一个服务的起始时间不早于当前工作日的开始时间,则表明该顾客车辆没有放置过夜。因此,若表达式的值为真,则表明顾客是在本工作日到达的;若表达式的值为假(False),则表明顾客车辆被放置过夜。 下面,我们来跟踪一个上述表达式值为“真”实体,即在本工作日到达的顾客。这个实体被送到名为Update Day Times 的Assign模块,在那里把实体的Book Time属性值累加到变量Day Book Time中,同时,把实体的实际服务时间值(TNOW -Start Time)累加到变量Day Actual Time中。以上就完成了两个必要的更新。 在下一个Decide模块中,判断是否需要通过加班来完成该项服务。可通过以下表达式比较变量Day End Time的值和当前仿真时间(服务完成时间)来实现 Day End Time < TNOW 如果表达式的值为“真”,则表明这项服务在正常工作日之内没有完成。在这种情况下,我们需要更新变量Day Overtime的值。这步操作需要非常小心,因为我们只想把超过正常工作日的那部分服务时间(即加班时间)累加到该变量上。可通过下述表达式计算其值 TNOW - MX(Start time,Day End Time) 其中,MX是Arena的内部函数,用以返回其自变量参数中的最大值。如果服务在本工作日内开始,则函数返回Day End Time;如果服务在本工作日之后开始,则返回Start Time。 接下来这个实体将被送到名为Wait Job?的Decide模块。如果一个实体的服务不需要加班来完成,也会被送到这个模块。在这个模块中,我们将检查这是否是一个希望就地等待完成服务工作。如果不是,则实体将经由Fasle分支被送到Dispose模块,并从那里退出系统;如果是一项等待工作,它将被送到名为Job On Time?的Decide模块,在那里检验服务是否是在所承诺的时间内完成的。可通过下述表达式进行比较 TNOW<=(Arrive Time + Book Time + Wait Allowance) 所承诺的时间是Book Time加上Wait Allowance(初值为1小时)的值。如果表达式的值为真,则表明服务没有在承诺的时间内完成,是一项被拖期了的服务,实体将被送到其后的Assign模块,在那里相应的变量Day Wait Late的值递增1,然后实体退出系统;如果表达式的值为假,则表明服务在承诺的时间内完成,实体直接退出系统。 现在让我们退回去考虑对顾客的服务没有在当天完成的情况,此时车辆将被放置过夜。这时实体将被送到名为Calculate Days Held Over的 Assign模块,其中对各项的赋值如图5-15所示。在这里要非常小心,因为有的车辆有可能会被放置超过不止一夜。虽然这种情况极少,但还是有可能存在的。因此我们首先要计算出被放置的天数并且把它赋给属性Days Held,该值的计算如下 AINT((TNOW-Start Time)/12)+1 注意,该车辆已被放置了一夜,而且记住,一天的仿真时间长度为12个小时。这样,你就应该可以理解上述表达式的意义了。 (原书P206) 图5-15 车辆放置过夜情况下的赋值 在下一个赋值项中,我们将计算用以表示开始服务那天的正常结束时间的仿真时间点,并将其赋给属性Day 1 End。表达式如下: ((Workday-1-Days Held)*12)+9 如果你对上述表达式还不太理解,可以通过一些简单的例子加以验证。 下一项赋值是更新加班时间,即变量Day Overtime。这一步有点复杂,我们将分几部分来解释。表达式中前两项(不包括Day Overtime本身)计算服务第一天的加班时间(小时数),如下式: ((Day 1 End +3)-MX(Start Time,Day 1 End)) 式中的第一项表示服务第一天结束时的仿真时间(例如12,24等),减去第二项后(这一项的含义已经在前面介绍过了),返回一个界于零到三小时的值。然后再加上下面的表达式: MX(0,(Days Held-1)*3) 这项的值只有在顾客车辆的服务超过一天时才为正,如果这种情况发生,我们将对服务第一天以后的各天的加班时间赋值为3小时。然后加上最后一项: MX(0,TNOW-Day End Time) 这一项给出服务结束那天的加班时间。别忘了,当前仿真时间就是服务结束的时间。 下一项赋值更新变量Day Book Time,表达式的含义很明显。其后,通过计算下述表达式的值来更新变量Day Actual Time: TNOW-Start Time-(Days Held * 1) 这里我们需要明确,式中没有包括每天的第一个小时。因为规定了在每天的第一个小时,修理间是不可用的,而且规定了修理间容量调度类型为Preempt。这意味着当天结束时,任何未完成的服务都将被中断,在第二天修理间可用时(也即第二天开始一小时后),继续余下的服务。 最后一项赋值是对总的滞留天数进行更新。离开的实体将被送到Decide模块以判断这是否是一个希望就地等待的工作。这个模块连同其后模块的逻辑在前面已经讨论过了,此处就不再赘述了。 子模型中的最后一个模块用于清除实体,因此不会再有实体离开这个子模型。 5.4.7 控制逻辑 这个子模型的逻辑相当简单(图5-16给出了表示这些逻辑步骤的模块)。到目前为止,我们考虑的实体一般都与一个实际中的物体相对应。但是在这个子模型中,实体没有相应的物理意义,被称作逻辑实体,因为它们被用来实现模型中的某种逻辑或者改变系统的状态。每一个仿真日(每12个小时)将创建一个实体,用来释放被保持在维修车间中的预约服务,重新设定当天的预约工作量变量,计算一些时间量,然后再清除该实体。你可能已经注意到,在这个子模型中不存在进入和离开点。 (原书P208) 图5-16 控制逻辑子模型 Create模块用来每天创建一个实体。这里我们将详细说明此模块中非常有趣的一点,即模块中的First Creation项(创建第一个实体的时间)取为0.999999。它意味着实体是在每天的第一个小时即将结束前被创建的。在下一个模块中将发出一个信号,用来释放保持在当天预约队列中的所有实体,让它们进入等待占用修理间的队列。希望你还记得,修理间在每天的第一个小时是不可用的。所以你肯定会问:“为什么创建第一个实体的时间不是0或1呢?”假如你还没有问这个问题的话,那你真的应该问一下!下面我们来解释一下这个问题。如果你用0表示创建第一个实体的时间,则顾客车辆的到达时间将被在服务活动子模型中赋值为那一天的开始时间,而不是那一个工作日的开始时间;如果你使用1,现在假设在那一天开始时三个修理间都是可用的,那么第一个实体将被分配到修理间1,第二个将被分配到到修理间2,第三个到修理车间3。剩下的实体将进入队列等待。这看起来好像是正确的,但是请记住,我们要优先为希望就地等待的顾客服务。而在这种情况下,当天预约队列中的前三个顾客将首先得到服务,而不管它们的优先级高低。当余下的顾客进入队列时,将按照优先级高低排列顺序,而这才是我们所需要的结果。所以,我们才按上述时间创建第一个实体,也即在修理间变成可用状态之前的一个非常非常小的时间内发出释放当天预约服务的信号,使实体在进入服务前能排在队列中合适的位置上。 接着这个控制实体进入后面的“信号”(Signal)模块,如输入界面5-15所示。在这里发出一个信号,其值为变量Day的值。还记得在服务活动子模型中共有5个Hold模块,当信号发出后,它将释放目前 “保持” 在相应Hold模块队列中等待此匹配信号的所有实体。 (原书P209) 输入界面5-15 Signal模块 在发出释放当天所有预约服务的信号后,实体进入随后的Assign模块,在此把变量Wait Load和Day Load在当天的值重置为0,这是因为当日队列现在为空。在第二个Assign模块中,首先通过以下表达式计算当天是第几天: AINT((TNOW/12)+1) 接着,根据变量Work Day的当前值,计算变量Day Start Time的值,表达式如下: ((Work Day -1)*12)+1 最后,我们在变量Day Start Time上增加8个小时作为变量Day End Time的值,这里就不用对其进行解释了,相信大家都能理解。然后,实体被送到Dispose模块清除。 到这里我们就完成了对模型逻辑的建立,下面将探讨一个相当棘手的问题 ( 纠错! 5.5 找出并纠正模型中的错误 如果你参与开发过许多模型,尤其是大型模型,迟早会遇到这种情况,要么模型不能运行,要么运行的不正确。这是我们所有人都会遇到的。如果你正在创建的模型中出现了一个Arena能够检测到错误,而这个错误会导致模型无法继续运行,则Arena能帮助你快速方便地找到这个错误。也许到目前为止,你很可能已经遇到过这种事情了,否则,那你真是太幸运了! 将导致模型无法运行的典型错误包括:未定义的变量、属性、资源,未连接的模块,模块名称的重复定义,名称的错误拼写(更多的情况是,不管对错与否,前后出现的拼写不一致)等。Arena会尽力防止你犯这类错误,但是它不会为了使你不犯任何可能的错误而去增加相应的限制,因为这样将会导致你无法最大限度地拥有建模灵活性。当你试着检查或者运行一个新建的模型时,Arena会尽可能多地检测出模型中存在的错误。为了说明Arena的这个功能,我们将在前面所建立的模型中故意插入一些错误。建议你在改动模型前,先用不同的名称保存一份模型的备份,除非你觉得真的没有这个必要。 我们将引入两个错误。首先,打开服务活动子模型,删除在第一个进入点和第一个Hold模块(即Monday List)间的连接线;然后,打开第二个Assign模块(即Assign Start Time)的对话框,把对New Value的赋值由TNOW改为TNO。这两个错误是初学者(有时候包括有经验的人)容易犯的典型错误。在做了上述改动之后,单击Run>Check菜单选项或者“运行控制”工具栏中的“检查模型”(Check)按钮(),即可检查模型中的错误。Arena将打开一个 “错误 / 警告”窗口,其中包含以下信息: ERROR: Unconnected submodel entrance point 这条信息告诉我们这里缺少一条连接线(就是我们刚才删除的那条)。现在先找到窗口底部的Find和Edit按钮。如果单击Find按钮,Arena将会高亮显示存在错误的模块;如果单击Edit按钮,Arena将会直接显示出存在错误的那个模块的对话框。这样,Arena就能帮你发现并且修改存在的错误了。因此,单击Find按钮,加上我们删除的那条连接线。 修改完后,重新检查模型,将会出现如下错误信息: (原书P210) (中间部分的程序信息行) 这条消息告诉我们符号TNO(对Arena变量TNOW的错误拼写)未定义。单击Edit按钮,Arena将会直接显示出我们引入此错误的Assign模块的对话框。现在把这个错误改正过来。在进行模型检查时,如果发现用错了一个变量名称而你想找到它,或者只是想知道在什么地方用过某个变量,可以通过点击Edit>Find菜单选项,输入要查找的字符串,就可以在模型中找到匹配该字符串的所有位置。现在可以输入TNOW试试。如果由于某种原因,你忘记了错误是什么,可以点击Run>Review Errors菜单选项重新打开错误信息窗口,以查看最后的错误信息。 现在,我们将介绍Arena中由命令驱动的“运行控制器”(Run Controller),可用它来寻找和纠正逻辑与运行中的错误。在详细介绍之前,我们先定义三个即将用到的Arena变量:NQ,MR和NR,事实上在前面几章中已经见过它们了。许多Arena变量可用于建立模型逻辑,并且可以在模型运行过程中观察它们的变化。上面三个变量的含义如下: NQ(队列名称)——队列中的实体数目(队长) MR(资源名称)——资源容量 NR(资源名称)——资源中处于忙态的服务单元的数目 注意,这些变量的值在仿真运行过程中一般都会随时间变化而改变,所以它们描述的是仿真运行过程中某一特定时刻的状态。 Arena变量给出当前仿真状态的信息,由于它们是Arena的保留字,所以你不能重新定义这些变量的含义,或者把它们当作你自己定义的变量一样来处理。建议你花一些时间去浏览一下Arena的各种变量,可以在Arena帮助系统中找到它们。你可以先浏览一下变量概要,然后在需要用到某个特定变量的更多信息时再查阅其详细的定义。 现在,我们将打开“运行控制器”,来演示一些常用命令的用法。在这里,我们不对Arena的命令用法进行详细的描述。我们建议你通过帮助文档去自己学习并运用这些Arena命令,这样可以更好地掌握它们。 通过点击Run>Run Control>Command菜单选项,或者点击在“运行交互”(Run Interaction)工具栏上的“命令”(Command)按钮(),可打开命令窗口。此刻,模型已经可以运行了,但还没开始运行。注意当前时间为0.0。现在让我们通过VIEW命令查看模型的前四行代码。输入命令: 0.0 > view source 1- 4 屏幕将显示如下响应: (原书P211) (程序语句) “运行控制器”列出了由Arena模型生成的SIMAN仿真语言的前四行代码。这些代码对应着“生成预约呼叫”子模型中前三个模块,即Create-Assign-Decide,用以创建预约实体,赋初始、以及检验是否为仿真初始状态。注意,Arena包括一个额外的Assign操作块,作为我们所建立的模块的一部分。既然我们现在知道了这四行代码的意义,就可以看看执行这段代码到底会发生什么。首先,我们需要改变“运行控制器”的设置,以便它能显示所发生的情况。我们通过SET TRACE命令实现来实现,输入: 0.0 > set trace * 在运行模型时,这条命令实现了对Arena/SIMAN仿真语言执行的所有活动的跟踪。现在让我们只执行这四行代码。可利用STEP命令来执行,它使得Arena一步一步地运行模型的第一个、下一个、直到第四个操作块。输入如下命令: 0.0 > step 4 Arena/SIMAN仿真语言将产生如下响应: (原书P212) (第一部分程序行) 在时刻0.01,系统创建出一个实体,下一个实体创建被安排在12小时后。实体进入第一个Assign操作块(包含在Arena中的)并进行赋值操作。接着实体被送到我们所创建的Assign模块,在那里变量Day的值增加到5,变量Call Number被赋值为1。然后,实体被送到第二个Decide模块,以检验相应的条件。 现在,输入CANCEL命令以取消跟踪状态,并且通过GO UNTIL命令让仿真时间推进到时刻1.1。 0.0 > cancel trace * *** All trace options canceled. 0.0 > go until 1.1 Break at time:1.1 现在,系统处于仿真时间为1.1的状态,让我们来看看在队列中有多少实体在等待资源服务(资源:修理间1,修理间2,修理间3)。可利用SHOW命令来显示模型中队列里实体数目、队列编号、以及所有其它队列的状态,如下所示: (原书P212) (本页底部的程序行) 从上面可以看出,当前在队列Bay Queue中有15个实体,Arena赋给该队列的编号(Bay Queue的值)为3。在检验一个模型的时候,Arena给其中的每个资源、队列等都分配一个编号,用以在模型运行时加以内部参照。Arena为每项内容所赋的编号在本次运行和下次运行中可能是不一样的。所以要注意,如果你编辑并保存过模型,Arena记录下的内容可能会与上面显示的略有不同,因此在下一次运行模型的时候,Bay Queue的数值可能就不是3了。有一些办法可以强制让Bay Queue的数值为3,但在这里就不讨论了。 接着我们利用VIEW QUEUE命令来查看一下队列中的实体情况,如下所示(由于篇幅原因,在这里我们只显示出前两个实体): (原书P213-214) (程序行) 上面的信息显示了实体的内部编号以及所有其他属性值。Arena自己定义了许多属性以供内部调用,你或许也注意到了属性Arrive Time是由我们在所创建的一个模块中定义的。 由于现在有一些预约呼叫实体在队列中等待修理间资源,因此现在所有可用资源的服务单元肯定都已被分配完毕了。我们可以通过SHOW命令来检验一下,如下所示: 1.1 Hours > show NR(Bay 1),MR(Bay 1) NR(Bay 1)=1 MR(Bay 1)=1 为了更有趣些一些,我们现在通过ASSIGN命令再添加一些资源: (原书P214) (倒数第二段程序行) 这样,修理车间1资源的服务单元数目从1增加到2。由于多出来一个可用的资源,Arena于是把它分配给队列中的下一个实体。让我们再来看一下队列和资源的状态。 (原书P214) (最后一段程序行) 和我们所期望的一样,可用的资源被分配给了队列中的实体,现在队列中只剩下14个实体。你也许感到很吃惊,我们竟然可以随意改变资源的数目,但实际上这正是资源调度所能做到的。不过还要记住,Arena中有一些变量是用户无法改变的,例如,TNOW,NQ和NR。现在关闭命令窗口,终止仿真的运行。 到目前为止,你应该粗略地体会到了“运行控制器”是如何工作的。它让你可以直接接触到后台运行的SIMAN仿真模型。你应该花费一些时间来好好研究这些命令,并且至少要对SIMAN仿真语言有个大概的了解。 Arena中还存在一些稍微简单的、至少不是那么让人恐惧的方法,可以用来检验模型的正确性或者发现逻辑错误。最简单的方法是运用动画来显示模型的逻辑过程。但是,你首先需要花费一些时间来深入了解才能解决问题。“运行交互”(Run Interaction)工具栏提供了一些工具,你可能用得到。我们已经使用过了Check和Command命令选项,现在让我们了解一下Run>Run control> Highlight Active Module命令选项。 单击Navigate项目栏,然后运行模型。如果现在打开的是顶层模型(Top-Level Model)视图,你可以看到,当实体通过某个子模型时候,该子模型高亮显示的。在模型运行状态下,双击“服务活动”子模型,可以看到当实体通过模块时,这些模块被高亮显示。但是,在某些电脑上,由于系统运行的速度比较快,你可能只能看见有实体停留的模块被高亮显示,如Delay和Dispose模块。如果不相信的话,可以通过缩放操作来使得整个屏幕只显示一或两个模块仔细进行观察。单击GO或者Step按钮,将看到Arena在模块间来回跳动以显示当前的激活模块。但是由于运行的速度太快,通常看不到全部模块依次高亮显示的效果,不过,它至少是在努力给你显示出这样的效果来。 如果你选择了如上设置,而当前窗口中又没有包括子模型中的所有逻辑模块,那么,Arena将每次改变窗口视图以显示当前不在窗口中的模块(只针对当前子模型中模块)。一般说来,所显示的模块被放于窗口中央,直到Arena需要调用另一个不在当前视图中的模块为止。尽管这可以让你看到更多的激活模块,但是在不同模块间的来回跳动显示会让人感到头晕目眩,所以我们建议你中止模型的运行,并返回显示所有逻辑模块的视图窗口。最后,如果想取消这种效果,可以通过停止模型运行并清除Highlight Active Module选项来实现。 你也可以通过更改某些选项,让模型在运行时显示所希望的效果。单击View>Layers显示如图5-17所示的对话框。此对话框可以在运行模式下打开进行设置。在这个对话框中,可以打开(选中)或者关闭(清除)各种不同的选项,让模型在运行时显示不同效果。 (原书P215) 图5-17 层次设置(Layers)对话框 现在,假设模型运行时出现了问题,而你怀疑错误出在“服务活动”逻辑中的Release模块上。如果在一个实体到达这个模块的时候,可以暂停仿真运行以查看状态,这就太好了。很幸运,Arena提供三种方法实现这种方式。你可以通过进入命令窗口直接进行相应的设置,或者采用更简单的方式,利用Run>Run control>Break On Module选项来实现。首先,你需要选中想要插入断点的模块,然后点击Run>Run control>Break On Module菜单选项,这会使得被选中的模块外出现一个红色框。接着单击Go按钮。模型开始运行,当实体到达你选中的模块时,运行将暂停,当然这可能需要一些时间。现在你可以检查错误(例如,可以不断地单击Step按钮逐步执行,直到发现错误之处),或者单击Go按钮继续运行模型,直到下一个实体到达此模块为止。当你不再需要插入这个断点时,先选取被插入的模块,然后通过再次点击Run>Run control>Break On Module菜单选项来取消中断。 你也可以运用Run>Run control>Break…选项或者Break按钮()在某一特定仿真时间、或某一特定状态、或在某一特定实体上设置断点。Break on Time(按时间中断)选项使得模型运行到所输入的时间时中止,这类似于Run Controller中的GO UNTIL命令功能。Break on Condition(按条件中断)允许你输入一个约束条件(例如,NQ(Bay Queue)>17),当模型运行到满足这个条件时中止。Break on Entity(按实体中断)在实体即将被激活时中止模型运行,对于这个操作,你需要知道实体的ID号码,可以通过Run Controller或者在仿真暂停时双击实体图形来查看。输入界面5-16显示了在时刻198以及按前述例子条件设置断点的情况。 (原书P216) 输入界面5-16 断点设置 另一个在运行过程中监测模型状态的好方法是定义watches。在我们定义之前,建议你先清除所有模块中的断点。单击Run>Run Control>Watch菜单选项或Watch按钮()打开监测(Watch)窗口。我们定义两个监测项 ( 一个是修理间队列中的实体数目,另一个是修理间1的状态,如图5-17所示(同时也给出了在监测窗口中显示的输出类别)。你可以定义任意多个监测项,如果你不定义标号项,Arena将用相应的表达式作为缺省标号。 (原书P217) 输入界面5-17 检测项定义 在关闭监测窗口前,单击Window>Tile菜单选项,则模型窗口和监测窗口将以横向排列的形式同时显示出来(单击监测窗口可使其激活为当前窗口)。在模型运行时,如果监测窗口为当前激活窗口,单击Go命令将会看到上述定义的两个表达式的值的变化情况。如果模型中存在动画,也可以看到动画情况。但是注意,表达式的值只有在监测窗口处于激活状态时才能看到不断更新的情况。 最后,在一个模型运行时,你也许想看到关于模型状态的报告。Arena允许你在模型运行的任何时候查看状态报告,只需简单地在工程工具栏中单击“报告”(Reports)面板就可以了。在模型运行的时候或者处于暂停的状态下均可查看报告。和监测窗口一样,你会看到动画式的运行状态变化,可以每隔一段时间查看一下报告而不必中止仿真运行。但是要记住,当你查看完报告后要关闭该报告窗口。 即使不用Run Controller,Run Interaction工具栏上的各种选项也为你提供了许多检查模型逻辑错误的便捷方式,而不需要你成为一个SIMAN仿真语言专家。在这里,我们建议你打开一个简单的动画模型,练习运用这些操作,熟悉其工作原理。虽然你可以等到用的时候再学习这些操作,但到那时,你不仅要学会用这些操作来查找错误,还要学习许多新的工具!与其把工作积到一起,还不如现在就解决掉。现在你已经知道如何使用这些工具了,我们就可以进入下一节,为汽车维修店模型增加动画效果。 5.6为汽车修理店模型添加动画效果 在前面我们已经提到过,这个模型与先前那些模型有所不同,因为在这里很难确定对哪些模块添加动画效果。本模型共分为四个基本部分:预约呼叫、服务活动、性能指标计算和控制逻辑,其中大多数部分不需要动画效果。但是,我们可以使预约呼叫和服务活动具有动画效果。 下面就从预约呼叫状态开始。在前两个子模型,即生成预约呼叫(Generate Appoint Calls)和预约服务(Make Appointment)中,包括了生成预约服务的逻辑过程。回忆一下,在生成预约以及把预约实体放到队列中等待服务日时,我们用到过一些主要变量。我们动画设计的第一部分就针对这些主要变量和五个预约队列。完成动画设计后,可以得到如图5-18所示的画面。 (原书P218) 图5-18 预约呼叫状态的动画表示 我们选定三个感兴趣的变量——当前安排的Book Time小时数,当前某日的预约数量以及该日当前等待服务的顾客数量。第一个和最后一个变量可以用我们定义的两个数组变量表示,即Day Load 和Wait Load。对于某天的预约数量,尽管没有定义过该变量,但我们把这些预约放在了一个队列中。因此,我们可以利用Arena的变量NQ来对它添加动画。我们可以利用动画工具栏中的“变量”(Variable)按钮()来添加动画变量。 下面给出一些在模型中添加动画效果的建议。如果在同一个动画设计中存在多个变量或队列,一般要求这些设计具有相同的外观。首先,添加第一个变量,输入数据,选择颜色并设定好大小形状。以后再添加时,可以单击Snap()按钮,这样可以很容易地创建另外一个大小和间隔都相同的变量。一旦第一个变量的设置完成,就可以运用Copy和Paste命令复制出四个相同的变量,然后再对每个复制出的变量进行相应的设置即可。在我们的动画设计中,可单击绘图工具栏上的Text按钮()添加相应的变量标识说明。 可以按照上述复制/粘贴的方式逐个添加新对象,或者先选中所有对象(变量、文本等),然后再用Copy和Paste命令进行复制粘贴,然后把这些复制出来的对象放到合适的位置,并编辑相应的属性。这种方法可以减少很多不必要的工作,而且保证了所添加的动画对象具有统一的外观。 除了以上的变量外,我们还在动画设计中添加了五个预约队列。我们仍建议你先设置好第一个队列Monday Appointment Queue,加上所要的背景,然后利用Copy和Paste命令添加剩下的四个队列。尽管在这部分动画设计中没有实体的运动,但我们能够对预约的状态变化有个直观清晰的了解。 服务活动部分的动画设计如图5-19所示,我们为三个修理间设计了相应的图形,并在每个资源图形的下面添加了文本,以显示相应的修理间编号。这里,我们再一次建议你充分利用Copy和Paste命令的便捷性进行添加操作。接着,单击动画工具栏上的Queue按钮添加队列Bay Queue,并且选择点状队列,我们在队列中选取24个点位,然后按图5-19所示布置各个点的位置。进行这个操作前,最好先打开Snap to Grid选项,这样比较容易对齐。我们建议在设置完前三个或四个点后,先运行模型来检验间隔是否设置恰当,然后再进行余下的工作。 (原书P219) 图5-19 服务活动部分的动画设计 在实体图形设计部分,我们先用Arena自带的基本图片库。我们用图片Blue Page和Red Page来表示预约实体,并切掉页面图形的底部以节省队列动画空间。在修改完图形后,它们会被保存在.doe为扩展名的模型文件中。这些更改并不会影响以后创建的新模型。接下来打开文件Vehicles.plb,选取一个红色车辆的图片添加到本模型的图片库中,用它表示就地等待服务的顾客车辆。然后,复制一份该图片,把新图片的汽车颜色改为蓝色,用这一图形表示正常状态的车辆。 最后,我们添加一个时钟和显示星期的对象到模型中,如图5-20所示。通过添加时钟,观察者可以得到动画显示的仿真时间的当前状态。回忆一下,在这个模型中,一天的仿真时间为12小时,并且要在第一个小时内处理预约呼叫,紧接着是8小时的正常工作时间和最后3个小时的可用加班时间。因此,我们的时钟设计为0到12。单击“动画”工具栏上的Clock按钮(),在12小时制和24小时制中选择前者。但是,如果我们仿真一天的时间不是12或者24小时,而是其他某个值,则无法利用此按钮选项设置了。下面,我们来介绍一下怎么按自己的要求创建时钟。 (原书P220) 图5-20 时钟和日期指示器 我们的时钟利用两个动画变量来显示,由冒号隔开。其中第一个变量表示当前小时数,第二个变量表示当前分钟数。下面来看一下怎么计算出这些变量的值。 首先计算出当前小时,如下表达式 AINT(TNOW-AINT(TNOW/12)*12) 将返回由Arena变量TNOW得出的当前小时。AINT函数返回参数的整数部分,即对表达式的值截断取整。可以很容易地验证上述表达式的正确性。这里返回的时间是基于12小时制的。要在动画过程中显示小时,只要选择动画工具栏中的Variable选项,并输入上述表达式即可。 计算当前分钟更容易一些,尽管表达式看起来有点复杂。如下表达式 (TNOW-AINT(TNOW))*60 将返回当前分钟值。 如果你想让当前小时和当前分钟变量显示相同的外观,建议你首先设置好当前小时变量的大小外观,然后运用复制、粘贴和编辑操作得到当前分钟变量。 接下来,添加日期指示器到模型中。单击动画工具栏中的Global按钮(),打开 “全局图形布局”(Global Picture Placement)窗口,如输入界面5-18所示。这个窗口与实体以及资源图片窗口类似。首先输入一个表达式(在本例中为变量Day),然后为这个表达式关联一张带有触发值(Trigger Value)的图片。你可以定义任意多对(触发值,图片)以显示所需要的图形。在关联图片时,首先创建相应的图形,与创建实体及资源图形一样,只不过这些图片关联的是所输入表达式的当前值。在本模型中,表达式Day的值在每次开始仿真的时候都被置为4,接着增加到5,然后变为1,接下来每隔12小时增加1(当增加到6时被重置为1)。指示器显示的初始符号为THURSDAY。当变量Day的值变为5后,符号显示为FRIDAY,然后随着时间变化为MONDAY等。 (原书P221) 输入界面5-18 用于定义当前日的“全局图形布局”窗口 为了保证所有的符号统一外观,我们先创建第一个符号,MONDAY,然后再通过复制、粘贴和编辑建立其它符号。关闭“全局图形布局”窗口后,需要在模型中的适当位置放置全局变量符号,操作方法和放置文本一样。然后可能需要改变这些符号的大小,可以在模型窗口里直接更改,也可以重新打开“全局图形布局”窗口,通过设置“缩放系数”(Size Factor)来改变所显示图形的大小。最后为变量添加标签,并在变量和符号上添加一个框。最终的动画图形如图5-21所示,图中显示的是第一次仿真中的第一天的情况。 (原书P222) 图5-21 汽车维修店动画设计 当你完整地运行完模型后,在分类总结报告中将给出十次重复仿真运行的情况汇总(你也可以通过Reports面板上的Category by Replication选项查看每次运行的情况)。尽管我们将不显示完整的分类总结报告,我们还是会介绍其中一些感兴趣的统计结果。由于对这个模型我们选择了独特的性能指标,因此只对这个报告中的两部分感兴趣。第一部分统计数据是修理间的资源利用情况。三个修理间每天被使用的时间大约都为7.8小时,这也许意味着我们应该增加每天所允许安排的Book Time小时数,即Max Load变量的值。我们将在6.4节作出这些变更(并在那里对这个变更的影响做适当的统计分析)。 我们感兴趣的第二部分是分类总结报告中的输出统计,如图5-22所示。平均每天加班时间为1.8小时,平均每天利润为$536.14。注意,修理间每天的平均使用时间仅为7.8小时,而每天平均加班时间却为1.8小时,可以看出这个系统的不确定性程度很高。我们也将在第六章详细讨论这个问题。 (原书P223) 图5-22 汽车维修店输出统计 如果在学习本章的过程中,你还没有试着建立自己的模型,那么现在可以打开我们创建好的模型(Model 05-01.doe),并在各个模块中浏览一下,以确认自己已经了解了我们所讲述的各种概念以及特征。 5.7 模型5-2:进一步完善汽车维修店模型 现在假设你已经完成了模型设计,并且请客户进行了运行体验,而客户则发现模型中遗漏了一些东西。这种现象在现实世界中经常发生。客户在原来描述问题的时候,忘记了告诉你两个主要的问题,以至当前的模型中缺少了解决这些问题的能力。第一个问题是,并不是所有的服务都能在任意一个修理车间进行。为了降低设施费用,客户对修理间2和修理间3进行了全面装备,使得它们能完成所有的工作。但是修理间1只能为一部分顾客提供服务(40%)。第二个问题是,并不是所有的顾客都在一天的开始时到达。实际上,还存在一些顾客根本就不来的情况。经过对历史数据的统计分析发现,大约60%至70%的顾客能按约定准时到达。在模型设计中,我们假定这个比例服从参数为0.6到0.7的均匀分布。余下部分的顾客一般在随后的两个小时内随机到达,偶尔会有一个顾客不来。我们对这些数据进行了分析,将在后面把结果告诉大家。 5.8模型5-2建模中的新问题 从建模的观点来看,这里涉及到几个新的概念。为了解决上面第一个问题,我们引入一个新的集合,并且重新考虑模型的逻辑结构,以使修理车间资源得到最有效的利用。对于上面的第二个问题,我们将更改顾客到达的过程,并找出一种方式来对迟到的顾客建模。 5.8.1 集合与资源逻辑 在新模型中,仍保留修理间资源集(集合Bays),但是只有一部分服务是由这个集合提供的。因此,必须创建一个新资源集合,在这个集合中只包括修理间2和修理间3,它们向其余的顾客车辆提供服务。然后要设置优先级,以更有效地利用资源。一般来说,我们需要把以上两种不同类型的顾客分配到两个不同的队列中。下面,我们将介绍Arena如何为等待的实体分配资源。 如果所有等待资源的实体都处于一个相同的队列中,那么分配资源的过程是比较明了的。但是,如果一个模型中存在多处地方可能分配同一资源的情况(不同地方有不同的Queue-Seize组合),这时候就需要使用一些特殊的分配规则。首先,我们来考虑一下为实体分配资源时可能遇到的不同情况: · 一个实体需要有资源提供服务,而且现在该资源是可用的 · 资源变为可用状态,而且需要资源提供服务的实体处于同一个队列中 · 资源变为可用状态,而且需要资源提供服务的实体处于不同队列中 对于前两种情况,资源分配相对较为简单,但我们还是介绍一下如何进行的。 如果一个实体要求资源提供服务,并且资源现在是可用的,则没有什么要考虑的,资源直接被分配给该实体。对于第二种情况,资源可用,但是有多个实体排在一个队列中等待该资源提供服务,此时则把资源分配给队列中的第一个实体。这种情况下,关键因素是如何确定实体在队列中的排列顺序。Arena提供四种排队规则:先进先出(First In,First Out:FIFO);后进先出(Last In,First Out:LIFO);低优先权值优先规则(Low Value First);低优先权值优先规则(High Value First)。其中,FIFO是默认规则,按照实体进入队列的先后顺序排列其位置。LIFO把最后到达实体放在队列的最前面(类似于堆栈)。最后两条规则根据每个实体的优先级别来排列顺序,其中级别可定义为相应的表达式并赋给实体的某个属性。例如,当实体到达系统的时候,可以将每个实体的交货期赋给相应的优先级属性。如果你选择Low Value First规则,就相当于按照交货期来确定队列中实体的排列顺序,交货期紧的实体排在前面。 如果需要资源提供服务的实体处于不同的队列中,情况则有点复杂。首先,Arena会比较各队列相对于该资源的占用优先权。如果一个队列的占用优先权值比其他的小(即优先级高),则资源被分配给该队列中的第一个实体。如果所有队列的优先权值相等,则Arena运用一个默认规则来选择,即资源被分配给等待时间最长的实体,而不管它在哪个队列中。因此,这实质上是一种FIFO规则在具有相同优先权的多队列情况中的应用。这意味着如果多队列中实体按照最早交货期规则排列,则可能出现满足该准则的实体却分不到资源的情况。例如,一个已经被延误的实体可能刚刚进入某个队列,而另一个交货期绰绰有余的实体却已经在另一个队列中等了一段时间了,此时资源会被分配给等得时间长的实体,而不是分配给交货期紧的实体。 Arena提供了一种解决这种问题的方式,即共享队列(shared queue)。共享队列如它的名称所显示的一样 ( 两个或者更多的占用活动共享同一个队列。这可以让你定义一个队列,把模型中所有需要资源服务的实体都放在里面,而不管它们的占用行为发生在什么位置。Arena将记录每个实体的位置信息,以保证在共享队列中的实体分配到资源后能按模型逻辑被送往相应的位置。这解决了模型中存在多个位置要求分配同一种资源的问题,但并没有解决在含有某些公共资源的不同集合中占用资源的问题,而这正是我们的模型中存在的情况。我们将很快介绍如何解决这一问题。 5.8.2 非平稳达到过程 通过改变模型来限制准时到达的顾客的数量是相当容易实现的,我们将在5.9.2节加以介绍。不同之处在于迟到的顾客的到达过程,其到达率是随时间变化的。这种类型的到达过程在服务系统中相当典型,需要用一种不同的方法来解决。许多系统的到达过程都按平稳泊松分布(stationary Poisson process)来建模,在这种分布中,每次到达一个顾客,并且顾客的到达相互独立,平均到达率不随时间变化。这意味着到达间隔时间将服从一个固定均值的指数分布。对于那些对概率不太感兴趣的用户,并不需要完全理解这个分布的含义,只要能利用这种分布来表示模型中的到达过程就可以了。在我们以前建立的大多数模型中(不包括模型4-5,那个模型只是为说明一个特殊知识点而建立的),都用到了这种概率分布。在第四章的“电子装配与测试系统”中,零件B的到达过程对该分布稍微做了一点变化。在那个例子中,我们假设到达过程是按照四个零件一批来进行的,但每批的到达情况仍服从平稳泊松分布。 在本节模型中,未按时到达的顾客的平均到达率是一个时间的函数。这种类型的到达过程通常都按非平稳泊松分布(nonstationary Poisson process)来建模。一个想当然(但并不正确)的建模方法是,对Create模块中的Time Between Arrivals(到达间隔时间)栏输入一个指数分布,并用一个用户定义的变量作为均值,然后根据当前时间段的到达率改变这个变量值。在我们的例子中,需要每15分钟更改这个值一次。如果不同时间段的到达率变化不大,上述方法可以提供一个近似正确的结果。但是如果到达率变化很大,这种方法将会给出误导(以及错误)的结论。为了说明这个问题,最简单的方法是考虑如下一个极端情况的例子。假设在模型中只有两个时间段,每个时间段30分钟。第一个时间段的到达率是3(平均每小时到达数),或者说平均到达间隔时间为20分钟;第二个时间段的到达率是60,或者说平均到达间隔时间为1分钟。假设第一个时间段中最后一个实体在第29分钟到达,我们将用平均到达间隔时间20分钟产生下一个到达的顾客。利用均值为20的指数分布很容易得出下一个实体的到达间隔时间会大于31分钟。1 这将导致在下一个时间段没有顾客到达,而实际上,下一个时间段的期望到达数为30。2 一般说来,在从一个时间段到下一个时间段、且到达率变大(或到达间隔时间减小)的情况下,利用这种简单的方法会导致第二个时间段内的到达数被错误地减少。同理,在到达率变小或到达间隔时间增大的情况下,会导致第二个时间段内的到达数被错误地增大。 学会正确地建模并运用此类到达过程是非常重要的,因为大多数情况下到达过程都会呈现这种特征,如果忽略了非平稳这个特性模型就会产生严重的误差而影响其有效性,因为到达的高峰与低谷会很明显地影响到系统的性能。幸运的是,利用Arena在Create模块中的内置功能可以正确地生成非平稳泊松到达过程。我们将在5.9.2节介绍如何运用此方法,更基础的方法将在12.3节介绍。 5.9构建模型5-2 因为在新模型中有两个与原模型不同的地方,我们将把它们当作两个附加的问题加以解决。首先,我们针对三个修理车间并不是都能提供所有服务这一问题来对模型进行相应的变更。解决完这个问题后,再处理顾客到达问题。 5.9.1 构建修理间模型 在模型5-1中,需要进行三处基本逻辑修改,以正确描述三个修理间的服务。首先,需要定义一个新属性来表示新任务的类型。接着还需要增加一个新的集合,在这个集合中包含两个能提供所有服务的修理间资源。最后,还需要更改服务逻辑。我们将按照上述顺序对模型进行修改。 首先,我们要在“生成预约呼叫”子模型中名为Assign Appointment Attributes的Assign模块中增加一条赋值。所要赋的值由离散分布DISC(0.60,1,1.0,2)产生,并把其赋给一个新属性Job Type(任务类型)。如果所赋的值为1,则表示可以在任何一个修理间接受服务;如果值为2,则只能由修理间2或3提供服务。接下来要定义一个名为Bays 2 or 3的集合,这个集合的成员包含可以提供任何类型服务的修理间2和修理间3。 现在我们需要更改“服务活动”子模型中的逻辑。新的逻辑如图5-23所示。观察一下这个逻辑图,你可以看出左面的五个Hold模块和模型5-1是一样的。 (原书P226) 图5-23 新的服务活动逻辑 第一处变更在Assign模块Assign Entity Picture中。在这里我们需要识别动画中两种新的任务类型。为了达到这个目的,我们在Vehicle图形集合中增加两种新图形。首先分别复制红色车辆和蓝色车辆,并把它们的车门颜色改为黄色。现在这个集合中包括了如下四种图形:Red Car(红色车辆),Blue Car(蓝色车辆),Red Yellow Car(红黄相间色车辆)和Blue Yellow Car(蓝黄相间色车辆)。其中红色车辆的优先权值为1, 任务类型(Job Type值)为1;蓝色车辆的优先权值为2,任务类型为1;红黄相间色车辆的优先权值为1,任务类型为2;蓝黄相间色车辆的优先权为2,任务类型为2。回忆一下,优先权为1表示顾客希望就地等待服务,而工作类型为1表示可以在任何一个修理间接受服务。新的图形集合中元素的引用表达式如下: Vehicle(Priority+(AINT(Job Type/2))*2) 当你观看动画显示的时候,就可以分辨出这两种不同类型的任务了。 对子模型余下部分的更改包括,在此Assign模块之后插入一个新的Decide模块,并增加一行处理新任务类型的新模块。这个新Decide模块用来把属于任务类型1的实体送到上面一行的模块中,即条件为True的出口,这些工作能在任一修理间完成。那些只能在修理间2或3接受服务的工作(任务类型值为2)将被送到下面一行的模块中,即False分支的出口。上面一行中的四个模块除了有一个小的改动外,和模型5-1中的几乎一样,我们将在后面加以介绍。 通过运用“复制/粘贴”命令来建立下面一行的四个模块,然后根据需要对模块参数进行相应的更改。首先,更改模块名称以保证其唯一性,接着打开新的Seize模块(Seize Bay 2 or 3),把资源名称改为Bays 2 or 3(我们刚定义的新集合)。对下一个集合的修改需要做出一些解释! 我们现在有两个Seize模块用以描述对修理间资源的占用。上面一行的模块可以使用所有三个修理间资源,而下面一行的模块只能使用修理间2或3。需要找到一种方法设置优先级,以更有效地利用修理间资源。在我们的模型中有两个层次的优先级。第一个层次是确定队列中实体的排列顺序。当我们把新Seize模块的名称改为Seize Bay 2 or 3时,系统同时更改了与之相关联的队列的名称,即Bays2 or 3 Queue。现在每个Seize模块都有一个相应的队列。两个队列都根据Priority属性值(顾客优先级)按照Lowest Attribute Value规则排列实体。这意味着希望就地等待服务的顾客将排在队列的前面并首先得到服务。因为修理间1只能分配给上面一行的Seize模块,所以我们只要考虑如何分配修理间2和3就可以了。由于在下面一行的Seize模块中的实体只能被分配到修理间2或3,因此我们将为这行Seize模块赋予比上面一行Seize模块更高的优先级(资源占用优先级)。 首先解释一下我们的模型逻辑,然后再介绍如何实现。我们将只考察每个队列中的第一个实体以及修理间2和修理间3。如果两个队列中的第一个实体都是就地等待服务的顾客,且修理间2或3现在可用,那么我们将把资源分配给Job Type 为2的实体,因为这种类型的实体只能占用修理间2或3,而另外一种类型的实体可以占用任意一个修理间。如果两个实体都是希望把车辆留下的顾客(优先级均为2),则可以采用与上面相同的逻辑。我们在设计逻辑时,要保证优先为就地等待的顾客(优先级为1)提供服务。 可以通过在两个Seize模块的Priority域设立如下表达式来实现上述逻辑。对于上面一行的Seize模块,表达式为 (Priority*10)+1 对于下面一行的Seize模块,表达式为 Priority*10 这将会得到如下优先级结果: 顾客优先级为1且任务类型为1的实体,其资源占用优先级为11, 顾客优先级为2且任务类型为1的实体,其资源占用优先级为21, 顾客优先级为1且任务类型为2的实体,其资源占用优先级为10, 顾客优先级为2且任务类型为2的实体,其资源占用优先级为20。 这些资源占用优先级的确定能使我们所设计的逻辑得以实现,因为它意味在相同顾客优先级的前提下,任务类型为2的顾客一般将首先得到服务。当你观看最后的动画时,就可以看到相应的效果。 对于余下的Assign和Delay模块,除了更改模块名称外,不需要作其他的改动。对这个子模型的最后一处更改是针对最后一个新Release模块的,我们把资源集合名称改为Bays 2 or 3。最终的更改是在动画中增加新队列Bays 2 or 3 Queue。 尽管优先级逻辑的定义有点不太好理解,但是相应的的修改工作却很简单。以上解决了我们新模型的第一个问题。下面我们将考虑更复杂一些的第二个问题 ( 顾客到达过程。 5.9.2 对顾客到达过程建模 为了解决第二个问题,我们必须修改顾客到达过程。在模型5-1中,在工作日即将开始的时候,释放预约队列中所有的客户预约服务。而在这个模型中,我们只需要释放一部分客户预约服务。我们还需要增加部分模型逻辑来描述后来的顾客到达以及最终删除预约队列中那些没有前来的顾客。所有这些逻辑都在“控制逻辑”子模型中添加,如图5-24所示。 (原书P229) 图5-24 新的控制逻辑子模型 首先,加入逻辑过程描述在每个工作日的开始只释放部分顾客的预约服务。这涉及对模型5-1中逻辑过程的两处修改(图5-24所示的第一行模块所描述的逻辑)。在Create模块后,我们加入一个新的Assign模块,Determine On Time Arrivals。这个模块的赋值内容如图5-25所示。在第一个赋值操作中,我们确定准时到达的顾客的数量,并把它赋给一个新的变量On Time。这只需从参数为0.6和0.7的均匀分布中产生一个随机数值,然后乘以当前预约队列中的预约数量,并对这个结果舍入取整(ANINT 函数)就可以了。接下来,从当天的预约数量中减去这个值,即可得到可能迟到的顾客的数量,并把它赋给一个新的变量Late。最后,我们定义一个新变量Total Late并不断更新其值,它表示迟到顾客的总数。你可能已经注意到了,这个值中可能包括没有前来履约的顾客。我们在迟到顾客总数中随意选择了某个数值作为爽约的顾客数。 ( 原书P229) 图5-25 确定准时到达顾客数的Assign模块 第二个更改是在紧接其后的Signal模块中进行的。在模型5-1中,信号的Limit域采用了默认设置,即允许Hold模块释放无限多个等待此匹配信号的实体。在这个新模型中,我们输入变量On Time作为Limit域的值。这将限制Hold模块只释放数量为On Time值的实体。如果现在运行这个模型看动画效果,你就会注意到并不是所有的预约服务都在每天开始时候被释放(为了看清楚这个情况,可能需要减慢动画的速度)。你可能还会注意到,被释放的实体都位于队列的前面部分,它们在队列中的位置由它们建立预约的时间决定,这看起来是个很合理的假定条件。 现在我们来建立考虑迟到顾客到达的逻辑,该逻辑过程表示在图5-24的第二行模块中。通过对实际中的有效数据分析发现,后来的顾客都会在工作日开始后的两个小时内到达。在对这些数据进行分析时,在这两个小时内每15分钟观察一次,共八次。这些时间段内的到达率分别为7,6,4,3,3,2,2和1(单位为到达数/小时)。首先,我们需要在Arena的Schedule数据模块中输入数据。先增加一个新的调度项Late Arrival Schedule,并在Type栏选择Arrival选项。 如果你一直跟着本书的讲解同时建立模型,别忘了模型中的调度要覆盖全天12小时,所以你可能需要在最后的一些时间段中补充定义一些0。如果你使用图示调度编辑器(Graphical Schedule Editor)来设置,首先需要打开Options对话框,并在Time Slot Duration中选择15 Minutes,设置Range栏为48(每小时4个时间段,共12小时)。然后就可以开始创建调度内容了,在第5到第12个时间段中分别输入上面给出的到达率即可。剩下时间段的到达率设为0。如果你以这种方法创建调度,看起来好像已经覆盖了全部48个时间段,但实际上只覆盖了前12个时间段(前面四个时间段到达率为0,后面的8个时间段到达率为正数)。 图示调度编辑器并没有假定每个调度都要覆盖一天(可以为任意时间长度)。在这种情况下,调度将在第13个时间段重新开始,因此我们实际上只定义了一天12个小时中的三个小时。我们应该在Options对话框中的When at the end of the schedule一栏选中Remain at arrival rate选项,并令右边的数值为0,这样才能得到第一天正确的调度。但是这样做带来的问题是,由于我们选择了用单次仿真模拟20天的运行情况,故此第一天以后的调度值永远都是0。因此,我们需要设法保证只是后九个小时的时间段(也就是最后36个15分钟时间段)的调度值为0。可以通过右击Schedule数据模块中的Durations项来定义,右击后选择Edit via Dialog(通过对话框编辑)或者Edit via Spreadsheet(通过数据表编辑)。选择Edit via Spreadsheet将打开如图5-26所示的Durations窗口,在窗口中可以通过双击来增加新行,并在其中输入Value(参数值)和Duration(相应的持续时间)组合。对于Arrival-Type(到达类型)的调度,默认时间单位通常是小时,所以对于有到达发生的八个15分钟时间段,我们输入持续时间为0.25。最后输入的一对数据(0,9)表示,在后九个小时时间段中调度值为0。这样就把一天全部12小时的到达率都设置好了。 选择Edit Via Dialog也将打开Durations对话框框,输入的内容与上面相同。如果在添加这些数值后重新打开图示调度编辑器,将显示存在非整数持续时间的信息。加入你采用的是15分钟(而不是0.25小时)作为时间段长度,你将能够看到图示的调度。注意,如果你要这样做的话,记住在退出图示调度编辑器时不要保存数据,否则刚才为最后部分新定义的零调度值将会被删除。 (原书P230) 图5-26 Durations数据表窗口 既然我们已经建立了到达调度,现在就来看一下有关的逻辑过程。输入界面5-19所示Create模块,将能够根据我们先前定义的非平稳泊松到达分布来生成实体(到达)。 (原书P231) 输入界面5-19 创建晚来的顾客到达 Create模块在每天的第一个小时内不产生到达,并根据输入的到达率产生第二个小时和第三个小时的到达,而在最后的九个小时内则没有到达。在其后的Decide模块中,通过查看变量Late的当前值来确定当天是否还有没来的顾客。如果这个变量的值为正,表明还会有顾客到达。如果表达式的值为True,则实体将被送到下一个Signal模块,在那里发出一个信号,其Signal Value域为变量Day的值,Limit域为1。这将使得当天预约队列中的下一个实体被释放出来得到服务。 然后,控制实体被送到其后的Assign模块,在这个模块中,变量Late的值减1。控制实体接着被送到这行的最后一个模块中并被清除。如果创建了一个控制实体,而所有顾客都已经到达(Decide模块中的表达式值为False),则实体将直接被送到Dispose模块。以上即为后来到达的顾客的所有逻辑过程。 不过我们还没有最后结束,因为还有可能在当天预约队列中的顾客实体不来了。我们增加最后一行逻辑结构来处理这种情况。第一个模块在第一天第3小时的时候创建一个控制实体,其后每12小时创建一个。然后这个实体被送到其后的Decide模块来判断变量Late的值是否为正。如果为正,则意味着实体将保留在当天预约队列中(也可以通过Arena变量NQ来查看队列中的实体数目)。所有这些实体都被认为是爽约的顾客。如果这个表达式的值为真,则实体将被送到后面的Remove(移除)模块。 Remove模块从队列中移除实体并把它送到模型中的另一个地方。这需要通过输入队列标识符和实体所在的位置(在队列中的位置,值为1表明在最前面)来指出所要移除的实体。如果你试图从一个未定义的队列中移除实体,或者所指定的位置大于队长,则Arena将终止运行并产生一个错误。在Arena中有两个可用的Remove模块,一个在Advanced Process(高等操作)面板中,另一个在Blocks(操作块)面板中。这里我们需要使用Blocks面板中的模块,因为需要为Queue ID输入一个表达式,用来表示Appointment Queues集合中的一个特定队列。Advanced Process面板上的Remove模块虽然允许你输入一个表达式,但是在你检验或者运行模型的时候会产生错误。 (原书P232) 输入界面5-20 Blocks面板中的Remove模块 我们逻辑结构中的Remove模块如输入界面5-20所示。在Rank of Entity部分(实体在队列中的位置)输入1,并在Queue ID处输入表达式Appointment Queues(Day)。队列中被移除的实体将被送到模块右边的底部出口点,也即被送到Dispose模块,从那里退出系统。原来的控制实体将从上面的出口点被送到下一个Assign模块。 在Assign模块中,变量Late的值减1,新变量Total Missed的值增1。后面这个变量表示爽约顾客的总数。也许我们应该对变量Total Late的值也减1。在当前模型中,变量Total Late的值也包括了爽约的顾客数,而我们忽略了这个小细节,这表明着我们建模并不很完美(大多数时候都会是这样的)。我们可以很容易修正这个小问题,在模型运行结束时从变量Total Late中减去Total Missed即可。但由于我们在评价系统主要性能指标时并不考虑它们,所以就不去修改了。完成赋值后,控制实体又被送回到Decide模块,以检查在当天预约队列中是否还有顾客。 以上完成了对“控制逻辑”子模型的逻辑更改。我们还对模型做了一个额外的修改,在Statistic数据模块中增加了两个输出项,用来输出平均每天晚到的顾客数量,以及平均每天没来的顾客数量。 (原书P233) 图5-27 模型5-2 汽车维修店问题的统计量输出结果 运行这个新模型,并与模型5-1的结果加以比较,将会发现修理间资源的利用情况大约为每天7.46小时(模型5-1中大约为7.8小时)。这与我们的预期相符,因为每天平均有0.765个顾客不来,这导致了模型5-2中大约有0.34小时的资源空闲时间。其它结果如图5-27所示。 如果把这些结果与模型5-1的结果(见图5-22)相比较,将会发现这个新模型的每天平均加班时间和平均利润都减少了。这是因为在新模型中存在爽约的顾客,所以这个结果是合理的。 到这里,汽车维修店模型的设计就结束了。在第六章中,我们将用模型5-2作为终态仿真统计分析的基础。 5.10 模型5-3:(s,S)库存系统仿真 在本章的最后,我们将研究一类完全不同的系统,即库存系统,通过分析对此类操作的建模,以表明系统仿真以及Arena的广泛适用性(不仅仅只能用来建立排队型模型3)。我们将只使用Blocks面板和Elements面板上的模块,主要为了说明它们的用途以及如何使用(实际上是如何使用SIMAN仿真语言)。在习题5-17中,我们会让你运用Basic Process和Advanced Process面板上的高级建模工具重新创建这个模型。这个模型实际上和Law and Kelton(2000)一书第1.5节中的那个模型是一样的。 5.10.1 系统描述 Bucky装饰品公司是一个多国仓储公司,它保存一种类型的产品(当然是一种装饰品)。由于装饰品是不可分割的,因此库存水平必须是个整数,在这个模型中我们将用I (t)表示,其中t表示从仿真开始到现在的时间(单位为天)。开始时,系统中装饰品的初始存量为60,即I (0) = 60。 顾客到达间隔时间服从均值为0.1天的指数分布(昼夜连续不停),且第一个顾客不在时刻0到达,而是在0时刻之后的一个到达间隔时间后到达。顾客需求为1,2,3,或4个装饰品的概率分别为0.167,0.333,0.333和0.167。如果当前库存能满足一个顾客的需求,则该顾客就会得到所有需求量并满意地离开。但是如果当前库存低于顾客的需求量,则顾客就取完现有的全部装饰品(有可能什么也没有),余下不足部分作为未交付订货,等到库存补充足够后顾客再取。通过允许库存水平I (t)为负值可以及时反映这种情况,虽然这没有什么物理意义,但却是种很方便的会计技巧。另外,还假定具有未交付订货的顾客会一直等下去,且从不取消他们的订货。如果库存水平已经为负值了(例如已经有未交付订货),而此时还有更多的顾客需求,则直接把需求量变负加到库存水平上即可。在这里,我们并不考虑未来到达的装饰品是用来满足哪些具有未交付订货的顾客的(因为他们非常礼貌,所以不需要考虑这个)。 在每天开始时(包括第一天开始时的0时刻),Bucky会查看库存水平以决定此时需不需要向某个装饰品供货商发出订单。如果库存水平值(可以为正或负)已经(严格)小于常数s(假定s=20),则Bucky将开始订货并使其库存达到另一个常数S(定义S=40)。这意味着如果订货能即时到达的话,则订货量将刚好能使库存水平增加到S。因此,如果t是一个整数,I (t)是某天开始时的库存水平(可能为正、负或零),且I (t) < s,Bucky的订货量将为S- I (t);如果I (t)( S,则Bucky什么也不需要作,只要在下一天开始时(也即在时刻t+1)再进行检查即可。由于采用了以上这种库存检查/补充方式,故这类系统通常被称为(s,S)存储模型。 但是,在一天开始时下的订单通常是不可能立刻到货的,而是在后半天的某个时候,即存在一个交货间隔期(也称为提前期),该间隔期服从以0.5和1天为参数的均匀分布。所以当订货到达时,库存水平将增加所订货物的数量;但是,如果在订单下达后有新的需求发生,则在订货最终到达,库存水平将是一个小于S的值。注意,在确定库存检查时间和交货间隔期时,要保证最多只能有一批订货在路上,以至于将不会同时存在超过一个订单,因为在一天开始时所订的货物最迟将会在这一天结束(也即在第二天开始)前到达,这是下另一个订单的最早时机。习题5-18能帮你更好地理解这些含义。 Bucky所感兴趣的是这个系统运行120天的平均总运作费用,该费用由如下三个部分组成: · 平均每天的订货费用(Average ordering cost per day)。每订货一次将花费$32(不论订货量大小),再加上每单位货物$3。如果没有订货,则不存在订货费用,甚至$32的固定费用也不存在。$3不是一个装饰品的(批发)价格,而是Bucky每订一个装饰品的管理费用(在这个模型中我们不考虑价格)。在120天仿真结束时,所有累计的订货成本除以120,即得到平均每天的订货费用。 · 平均每天的储存费用(Average holding cost per day)。无论什么时候,只要库存中有实际的产品(也就是说,I(t)>0),则储存费用为每天每单位$1。因此总的储存费用为 (原书p235第一个公式) (考虑一下),平均每天的储存费用就是总储存费用除以仿真时间长度,即120天。 · 平均每天的缺货费用(Average shortage cost per day)。无论什么时候,只要存在未交付订货(也就是说,I(t)<0),则缺货费用为每天每单位$5,比持有正的库存的费用更高。因此总的缺货费用为 (原书p235第二个公式) (再考虑一下),平均每天的缺货费用就是总缺货费用除以仿真时间长度。 注意在既没有库存又没有未交付订货的时段内(也就是说,I(t)=0),储存费用和缺货费用均为零,这正是成本会计师的天堂。你也可能注意到,我们没有考虑产品的批发和零售价格。在这个模型中,我们假设这些价格是固定的,由它们决定了相应的需求,因此收入和利润也是固定的,我们所能影响的只是运作成本。 在建立(很简单的)仿真模型之前再说明一点。在每天的开始时(即在整点时)检查库存情况,而且订货费用可以为任何数值。恰巧仿真运行也假设在整数时间(120)结束,所以通常在那个时间会有一次库存检查,从而发生一次永远都不会到达的订货,但我们却需要支付相应的订货费用。因此,我们应该避免在120这个时间点上检查库存情况,这可以通过在199.9999这个时间点停止仿真运行来实现(这是个偷懒的做法,习题5-19会让读者做进一步思考)。 5.10.2 仿真模型 正如前面所提到的,我们将只使用Blocks面板和Elements面板中的模块来建立这个模型。使用Basic Proess面板和Advanded Proess面板中的高层(而且比较现代的)模块会容易得多,但我们把它留为作业5-17。 图5-28显示了完整的模型,包括右上方的动画部分。Blocks面板和Elements面板中的模块位于图的底部,被分成三个部分。 原书p236 图5-28 完整的库存模型 我们首先分析一下模型的数据结构。图5-28底部部分的模块来自Elements面板,因此这些模块也被称作构模元素(elements)。注意构模元素互不相连,因为它们用于为整个模型定义各种对象。在使用这些构模元素时,你应该对许多术语已经熟悉很熟悉了,因为它们和Arena的许多高层构件和功能是类似的。 图5-29中给出了一个完整的“变量”元素(Variables),还显示出了其中的条目Inventory Level(库存水平),它用于定义Arena的变量及其初值(类似于Basic Proess面板中的Variables模块)。如果一个变量没有赋初值,则默认其值为零。请读者自己阅读模块中的条目,这些条目的定义如下: Inventory Level:在仿真中任何时刻的库存水平(可为正数、零或负数),其初值为60。这个变量即为函数I (t)。 Little s: 参数s,其初值为20。 Big S:参数S,其初值为40。 Total Ordering Cost:累加所有订货费用的统计累加器变量;不赋初值(初值默认为0)。 Setup Cost:订货的固定费用,其初值为32。 Incremental Cost:(每件物品的)可变订货费用,其初值为3。 Unit Holding Cost:一件物品储存一天的费用,其初值为1。 Unit Shortage Cost:一件订货未交付物品一天的费用,其初值为5。 Days to run:仿真的时间长度(以天为单位),其初值为119.9999(按前面所说的偷懒做法)。 原书p237 图 5-29 Variables元素 可通过图5-30所示的“表达式”元素(Expressions)来定义相应的四个表达式,图中给出了条目Demand Size(需求大小)的定义。这些表达式定义了一些数量的概率分布,可以很容易地根据名称来理解这些数量的含义。我们决定把Evaluation Interval (赋值间隔)定义为一个表达式而不是一个变量,即使它是一个常量(1),因为这将使模型更具一般性,将来可以使用一些随机的检查间隔(但是,在习题6-12中可以看出把它定义为一个变量也有其优点)。 “属性”元素(Attributes)只有一个条目 ( Order Quantity(订货数量),用来声明它是实体的一个属性。“实体”元素(Entities)声明了两种我们要使用的实体,Customer(顾客)和Inventory Evaluator(库存检查员)。“项目”元素(Project)可以用来指定项目的标题、分析员姓名和其它文档,也可以控制一些报告选项,类似于以前使用过的菜单选项Run>Setup>Project Parameters。这些模块中没有多少需要看的东西,这里将略过这些视图,读者可以自己查看。 原书p238 图5-30 Expressions构模元素 原书p238 图5-31 Replicate 构模元素 图5-31所示的Replicate构模元素基本上与Run>Setup>Replication Parameters菜单选项一样。其中只有两个输入项用非默认值,第一,把基准时间单位(Base Time Units)改成Days,因为所有的时间度量都使用天,而且Blocks面板的模块中没有提供指定输入时间单位的地方,这里假设都使用基准时间单位。第二,指定重复仿真运行时间长度(Replication Length)为变量Days to Run,这个变量的初值为119.9999,目的是避免在时刻120进行没用的库存检查。 图5-32给出了DStats构模元素及其Holding Cost数据项,它的作用与Statistics模块中对时间持续性变量的统计功能相同(也即Statistics模块的Time-Persistent部分),在这里,主要是累计储存费用和缺货费用。在图5-32中可以看到一部分SIMAN表达式 (原书p239第一个公式) 这是Inventory Level为正时的瞬时储存成本(回忆一下,MS是Arena的内置公式,用来求取并返回最大值)。与此类似,DStats构模元素中的另一个数据项Shortage Cost的SIMAN表达式为 (原书p239第二个公式) 这是用来计算缺货费用的。我们想要的是这些值的时间平均,可通过下面的方式得到。 原书p239 图5-32 DStats构模元素 原书p240 图5-33 Output构模元素 图5-33给出了Output构模元素,其作用与Statistics模块中的Output部分的作用相同,这里要做两件事。第一(在图5-33中已显示出),求取并输出每天的平均订货费用,用Total Ordering Cost除以Days to Run,然后将其保存在名为Avg Ordering Cost的输出项中。第二,把全部三个输出项加起来,即求出平均总成本(Avg Total Cost),表达式如下 OVALUE ( Avg Ordering Cost ) + DAVG (Holding Cost ) + DAVG (Shortage Cost ) Arena中的公式OVALUE返回其变元的最后一个(也即最新一个)值,这里是指在这个模块的前一行数据项中求出来的平均订货成本,前面的句子定义的东西(我们也可以不这样做,而是直接使用Total Ordering Cost/Days to Run来代替,但这样做的好处是能单独得出平均订货成本这个输出量,而这个量通常也是我们所感兴趣的)。Arena的公式DAVG返回时间持续型变量的平均值,所以在这里使用了两次以求取平均每天的储存费用和缺货费用(这两项同时也分别在报告中单独出现)。   现在来看一下Blocks面板中的逻辑模块,也被称为操作块(blocks)。图5-28最上面的一组操作块表示顾客到达,产生需求和离开。 图5-34中给出了“创建”(Create)操作块的输入界面,该模块需要输入三个非默认数据项。在First Creation和Interval两栏中输入Interdemand Time,该变量在Expressions构模元素中被定义为EXPO(0.1)。Entity Type(实体类型)定义为Customer。 原书p241 图5-34 顾客到达的Create操作块 图5-35中给出的“赋值”(Assign)操作块,是用来从当前库存量(Inventory Level)中扣除掉顾客需求量的。其中Demand Size已在Expressions模块中被定义为一个离散随机变量,其以适当的概率取1,2,3或4作为需求量。 原书p241 图5-35 定义顾客需求的Assign操作块 然后,Customer实体经由“清除”(Dispose)操作块离开系统。在Dispose操作块中唯一要做的就是把Record Entity Statistics复选框清空(在这个模型里不考虑实体的统计信息)。 图5-28中间的一组操作块表示了定期的库存检查和订货决策。如果有订货,就等待货物到来并增加库存水平;如果没有订货,那就什么也不做。 这个逻辑过程从Create操作块开始(见图5-36),在模型中插入一个计数器用于统计仓库中装饰品的数量,以决定是否下订单。如果下了订单则等待交货,然后把这些装饰品放入货架。最好把创建第一个实体的时间设为0 ,因为系统需要在运行开始时检查库存情况。实体类型是Inventory Evaluator(库存检查员),创建相邻实体的时间间隔由表达式Evaluation Interval来确定,它在Expressions构模元素里被定义为常数1。 原书p242 图5-36生成“库存检查员”实体的Create操作块 库存检查员一旦被创建,就进入“分支”(Branch)操作块(见图5-37),Branch操作块和读者已经熟悉的Basic Process面板中的Decide模块具有某些相同的功能。在这里,需要决定是否在此时进行订货。首先,以Inventory Level < Litter s作为条件添加If型分支,若条件为“真”,则表示此时需要进行订货(这个分支的对话框见图5-37);另一个Else分支表示现在不需订货,是唯一的其他可能。Branch操作块的离开点对应相应的分支条件。在这里,如果进行订货就选择第一个离开点(前往位于Branch操作块右上部的Assign操作块),第二个离开点对应Else分支,意味着什么也不做(所以实体直接进入位于Branch操作块右下部的Dispose操作块)。Branch操作块中的一个重要部分是定义最大分支数(Max Number of Branches),其值默认为无穷大(这里设定为1)。一般来说,Branch操作块按各分支的排列顺序检查各分支条件是否满足,把进来的实体(或其副本)从每一个条件为“真”的分支送出去,直到检查完所有的分支。这是一个很强大的功能,但是如果操作块中的各数据项处理不当的话很可能导致错误。 原书p243 图5-37 Branch操作块 如果要进行订货,则库存检查员实体进入后面的Assign操作块(见图5-38),首先为属性Order Quantity(订货数量)赋值为Big S - Inventory Level。操作块中的下一个赋值是计算这次订货的订货费用,把变量Total Ordering Cost赋值为下面的表达式 Total Ordering Cost + Setup Cost + Incremental Cost * Ordering Quantity 注意以上赋值顺序很重要,因为在第二个赋值中要使用第一个的结果。 原书p244 图5-38 进行订货的Assign操作块 现在等待订货到达,这需要通过把库存检查员实体送到图5-39中所示的“延时”(Delay)操作块来实现,他在这里停留Delivery Lag个时间单位(记住,在操作块中只有一种基准时间单位)。Delivery Lag在Expressions构模元素中被定义为UNIF(0.5,1.0)。 在经过了交货延迟时间后,库存检查员实体进入后面的Assign操作块(见图5-40),在这里为变量Inventory Level增加Order Quantity数量。 原书p244 图5-39 描述交货延迟的Delay操作块 原书p245 图5-40 描述订货到达的Assign操作块 在订货交付后,库存检查员实体的工作就完成了,进入最后的Dispose操作块。 现在为模型添加一点动画。图5-41所示的对话框给出了绘制变量Inventory Level随时间变化的散点图的过程。我们分别绘制两条曲线,红色曲线表示库存水平为负值,黑色曲线表示库存水平为正值。为了表示正的库存水平, MX(Inventory Level,0)对应的曲线绘制为黑色;对于负的库存水平,将表达式MN(Inventory Level,0)对应的曲线绘制为红色(MN是Arena的内置函数,用来计算并返回参量的最小值)。当在任何一个图中取0的时候,将会在0处得到一条水平线。 用某种方式观察库存本身的变化也是很有趣的。为此,我们在散点图的左边放置了一对水平(Level)动画元素(有时也叫作温度计式动画)。上面的动画图形(图5-42中的黑色图形)描绘了库存中装饰品的实际数量,用表达式MX(Inventory Level,0)表示,随着库存增加而上升。下面的动画图形(红色的那一个,这里就不再麻烦地画出来了)描述了未交付订货的装饰品数量,即MX(-Inventory Level,0)。当存在未交付订货的时候其值为正,但我们更想把它画在0水平线的下面,所以选择填充方向(Fill Direction)为向下(Down)。 原书p246 图5-41 散点图对话框 原书p246 图5-42 水平动画元素对话框 再添加一些标识后就可以运行了。观察散点图和水平动画图可以发现,当有需求时库存水平会下降,当订货到达时库存水平会上升。每天的平均储存费用为9.37,缺货费用为17.03,订货费用为100.39,总费用为126.79。(s , S)=(20,40)是不是最好的决策呢?这是一个很好的问题,在第六章最后的习题6-10和6-11中将会要求读者来解决。 5.11 小节 这一章对详细的底层建模能力和相应的调试及动画等问题进行了较深入的探讨。我们介绍了一些有关SIMAN仿真语言的使用内容,当然很不全面,读者可以参考Pegden,Shannon and Sadowski(1995)对SIMAN的完整介绍。到现在为止,读者应该已经掌握一个较为强大的建模工具库,可通过选择各种层次的建模构件来处理多种不同系统。在下面的几章中,我们将继续介绍Arena的其它建模能力。 5.12 习题 5-1 按模型3-1的形式建立在第二章中描述的模型,但是这次只使用Advanced Process面板中的模块来取代操作模块。使用动画工具栏中的散点图和动画变量来完善模型。运行20分钟并和前面得到的结果进行比较。 5-2 零件以均值为20分钟的指数分布间隔时间到达一个两机器系统。到达后,零件先被送到机器1加工,加工时间分布为TRIA(4.5,9.3,11)分钟。然后零件以分布TRIA(16.4,19.1,21.8)分钟在机器2上加工。在机器2上加工完的零件再被送到机器1上第二次加工(加工时间不变)。然后零件离开系统。单次运行仿真20000分钟,观察平均队长和平均系统逗留时间。 5-3 文件到达间隔时间为EXPO(10),被送去进行剪切,所有时间单位为分钟。有两个剪切器,一个主要的和一个备用的。所有到达的文件被送到主要剪切器那里。如果主要剪切器前面的队列长度小于5,则文件进入队列等待剪切,操作时间为TRIA(9,12,15)。如果主要剪切器前面的队长已经是5,则文件被送到备用剪切器(队列容量为无限大)处理,操作时间为TRIA(17,19,21)。当主要剪切器处理完25份文件后,必须关闭进行清理,时间为EXPO(30)。在这段时间内,主要剪切器队列中的文件将等待。制作动画,运行模型5000分钟。统计系统逗留时间、资源利用率、队长和排队时间。尽可能使用Advanced Process面板中的模块。 5-4 卡车以间隔时间EXPO(9)到达有三个码头的卸货区。码头1、码头2和码头3的卸货时间分别是TRIA(25,28,30)、TRIA(23,26,28)和TRIA(22,25,27)。如果有一个码头空着,卡车立即到那个码头去。假设卡车到所有码头的行进时间为0。如果有两个以上的码头空闲,卡车选择码头的顺序是(3,2,1)。如果所有码头都忙,则选择队长最小的码头。如果有两个以上码头的队长一样,选择码头的顺序是(1,2,3)。用Advanced Process面板中的模块建立仿真模型,使用Basic Process面板中所需的模块完善选择逻辑。运行模型20000分钟,统计码头利用率、队长、排队时间和系统逗留时间。 5-5 吊扇套件以TRIA(2,5,10)时间间隔到达装配系统(所有时间单位为分钟)。有四个装配操作员,套件被自动送到第一个空闲的操作员处装配。套件装配时间和操作员有关,如下表所示。 操作员 装配时间 1 TRIA(15,18,20) 2 TRIA(16,19,22) 3 TRIA(16,20,24) 4 TRIA(17,20,23) 装配完成后,经检验发现大约有7% 有缺陷。有缺陷的吊扇被送回装配它的操作员处修理。这些有缺陷的吊扇比新到的吊扇有更高的加工优级先。因为这些吊扇要先分拆然后重新装配,所以修理时间比一般装配时间多30%。运行模型20000分钟,统计操作员利用率和系统逗留时间。 5-6 习题5-5中的吊扇装配质量控制人员决定,如果一个吊扇两次没有通过检验就要被送到另一个地方返工。对模型进行必要的修改然后运行20000分钟,比较两次仿真的结果(每个模型只运行1次)。同时跟踪返工的吊扇数。 5-7 建立一个有三个工作站的串行生产线模型,生产线的检验拒绝率很高:每个工作站均为7%。被第一个工作站拒绝的零件被送到废料库;被第二个工作站拒绝的零件回到组装它的第一个工作站重新加工,重新加工的时间与原来的加工时间同分布,但增加50%(这个惩罚因子1.5只用于第一个工作站,返回第二个工作站时不需惩罚)。被第三个工作站拒绝的零件回到组装它的第二个工作站返工,在那里给予50%的加工时间惩罚(返回第三个工作站时不需惩罚)。工作站1、工作站2、工作站3的加工时间分别是TRIA(6,9,12)、TRIA(5,8.5,13)、TRIA(6.5,8.9,12.5)(所有时间单位为分钟)。零件到达系统的间隔时间为UNIF(6,14)。运行模型20000分钟,统计每个工作站的队长、废弃零件数、工作站利用率、没有被拒绝过的零件的平均系统逗留时间和最大系统逗留时间、至少被拒绝过一次的零件的平均系统逗留时间和最大系统逗留时间。此外,统计被拒绝过的零件的拒绝次数。 5-8 为了减少习题5-7中零件的系统逗留时间,可考虑一个新的优先级策略。队列中的优先级是基于一个零件被拒绝的总次数,不管是在哪里被拒绝,一个零件被拒绝的次数越多它在队列中的位置越靠后。采用这个新的优先级策略后,系统逗留时间有什么不同吗?(提示:使用队列数据模块,利用拒绝次数确定队列中实体的排列位置。) 5-9 零件以间隔时间EXPO(25)到达一个机加工车间(所有时间单位为分钟)。车间有两台机器,到达的零件用掷硬币的方法决定分到哪台机器。除了加工时间,两台机器的工作方式相同。当零件到达一台机器的区域后,操作员就把零件装在机器上(车间里只有一个操作员)。当加工完成后,操作员再把零件移走,然后零件离开系统(零件只需在一个机器上加工)。同一个操作员要完成所有的安装和移走零件的工作,等待操作员时间最长的机器优先操作。所需时间如下(采用三角分布形式): 机器号 安装时间 加工时间 移走时间 1 8,11,16 20,23,26 7,9,12 2 6,8,14 11,15,20 4,6,8 运行25000分钟,统计机器利用率、操作员利用率、按使用机器划分的零件系统逗留时间、总体系统逗留时间(不按机器划分)和每台机器等待操作员的时间(包括安装和移走)。使用存储器(storage)动画元素为安装、加工和移走过程建立动画。 5-10 一个小仓库为一个制造企业提供在制品储存服务。该企业生产四种不同零件,零件类型百分比和每个零件的库存费用为: 零件类型 百分比 单位零件存储费用 1 20 $5.50 2 30 $6.50 3 40 $8.00 4 50 $10.50 存储费用计算如下,例如,若目前的库存包括3个零件1,没有零件2,5个零件3和1个零件4,则当前的库存费用为 3 ( $5.50 + 0 ( $6.50 + 5 ( $8.00 + 1 ( $10.50 = $67.00 当零件到达和离开时,如下所述,存储成本将会上升和下降。 零件以时间间隔TRIA(1.5,2.0,2.8)到达(所有时间单位是分钟)。由两台起重机存入和取出零件,其存取移动时间为UNIF(1.2,2.9)。对零件的需求模式与零件到达模式相同。如果发出需求时仓库中没有所需要的零件,则作为未实现的需求加以统计。所有等待出库的零件都有优先级,优先级根据零件存储费用而定,费用高的优先。 对于零件的到达,在零件到达时增加存储费用,在零件入库后增加库存数量。对于零件出库,当有零件需求时即刻减少总的库存零件数,在零件取出后再减少存储费用。 开始时仓库中每种零件各有4个,运行模型5000分钟。统计起重机利用率、平均存储费用、仓库中每种零件的平均存储量、以及因为缺货而未能实现的需求数。 提示:使用下标变量表示零件的库存量和单位零件存储费用。(注意,为下标变量赋值时,需要在Assign模块中使用Other选项。)使用离散分布决定零件类型,使用Statistics数据模块收集所需的统计量。 5-11 一个中型机场有少数的国际航班到达,需要办理入境和海关手续。机场想要研究应该对多少乘客进行包裹检查,以及需要多少海关人员。到达的乘客必须先办理入境手续(入境手续不在这个模型的范围之内)。然后他们认领包裹,前往海关检查处。到达海关的间隔时间分布为EXPO(0.2),所有时间单位为分钟。现在的方案是安排两个海关检查员处理那些不用检查包裹的乘客,服务时间分布是EXPO(0.55)。一个新的机场系统分析员建立了一种概率方法,决定哪些顾客将需要检查包裹。这个决定在顾客将要进入海关正常队列时做出,决定过程如下:利用均值为7的泊松分布生成一个随机数,为了避免得到0,将这个数加1,并开始计数。当计数器达到所生成的那个数时,这个不幸的乘客将被送进第二个队列检查他/她的包裹。然后再生成一个新的检查数字,重新开始以上过程。单独有一个检查员处理这些乘客,服务时间分布是EXPO(3)。坐这些大型飞机到达的乘客人数服从240-350的均匀分布,仿真运行到所有乘客的手续办理完毕为止。建立以上系统模型并重复仿真运行20次,统计不同类型顾客的系统逗留时间(被检查和不被检查)和顾客数,以及检查员利用率。 5-12 一个国家驾驶执照考试中心想要分析它的运作过程以找出可能的改进。到达的顾客进入大楼拿到一个号码,这个号码决定他们在笔试队列中的位置,笔试是自助式的,可从5个电子考试台中选择一个来完成。考试时间分布为EXPO(8),时间单位为分钟。百分之十三的顾客不能通过考试(考试有很多问题,难度大)。这些未通过者会得到一本关于驾驶规则的小册子进一步学习,然后离开了系统(步行)。通过考试的顾客将选择两个摄影室中的一个去照相并领取新执照。照相时间分布是TRIA(2.5,3.6,4.3)。摄影室有各自的队列,顾客进入长度最小的队列排队,不管是否有人正在接受服务。如果两边队长一样,则选择最近的摄影室,即摄影室1。注意,这些规则可能会导致在两个摄影室都没人排队时(也就是两个队长都是0),出现不合理的顾客行为。当摄影室1忙、而摄影室2空闲时,一个来到照相区的顾客可能选择去摄影室1排队(根据相同队长的处理规则)而不是在摄影室2立即得到服务 ( 不过,这是因为他们看不见摄影室里面的情况!然后,这些顾客骄傲地拿着新执照离开系统。中心一天营业8小时来处理所到达的顾客,但会继续延长一小时服务来处理剩下的顾客。顾客在一天中的每个小时到达模式是不一样的,具体如下: 小时 每小时到达数 小时 1 22 5 35 2 35 6 43 3 40 7 29 4 31 8 22 仿真运行十天,统计平均每天考试未通过的人数、电子考试台与摄影室的利用率(全部电子考试台的整体利用率和每个摄影室各自的利用率)和平均队长、以及通过笔试的顾客的平均系统逗留时间。为所有电子考试台和摄影室添加动画。 5-13 国家执照管理局的一个办公室有两种到达。想购买新图版的人到达间隔时间分布为EXPO(6.8),服务时间是TRIA(8.7,13.7,15.2),所有时间单位为分钟。想要更新驾驶执照或申请新执照的人的到达间隔时间分布是EXPO(8.7),服务时间是TRIA(16.7,20.5,29.2)。办公室有两条队列,每种顾客一条。办公室有五个办事员:两个人负责图版业务(Mary和Kathy),两个人负责执照业务(Sue和Jean),一个组长(Neil)可以为两种类型的顾客服务。Neil将会为等待时间最长的顾客服务。假设五个办事员一天八小时都工作。注意,当位于多个“先进先出”(FIFO)队列(对应于多个Process模块)最前面的实体试图占用同一资源时,选择哪个实体“赢得”资源的逻辑与把所有的队列合并成为单一FIFO队列的情况相同。观察两种顾客的系统逗留时间。 5-14 习题5-13描述的办公室准备对Kathy进行多种能力培训,这样她就能够为两种顾客提供服务了。按这种考虑修改模型,看这样对系统逗留时间有什么影响。 5-15 改变习题5-14的模型,使每个办事员有30分钟的午餐时间。第一个人的午餐时间在第180分钟时开始,其后一个接一个,持续150分钟。午餐的顺序是:Mary,Sue,Neil,Kathy和Jean。这会对顾客的系统逗留时间造成什么影响? 5-16 修改习题3-10中的概率板(probability-board)模型,使得只要改变单个变量的值就可以立即改变所有木桩的右弹概率。运行模型,设置右弹概率为0.25,和习题3-10模型中的吹风情况进行比较。 5-17 不使用Blocks面板或Elements面板中的模块,只使用Basic Process面板和Advanced Process面板中的模块,重建模型5-3(库存模型)。 5-18 模型5-3中,在确定库存检查间隔和交货延迟时间时,我们使得在任何时间段内都不可能出现一个以上订货。如果改变这些数据,使得在给定时间段内可以有多次订货,那将会怎么样呢?模型5-3仍有效吗?(注意,在模型5-3中我们利用库存检查员实体的某一属性表示订货数量;如果订货数量用一个变量来表示会怎么样呢?) 5-19 在模型5-3中,不使用“偷懒的”仿真终止时间119.9999,而是就按准确的120分钟运行仿真,但要补充逻辑过程用以防止在时间120发生没用的库存检查。 对输出结果有什么影响? 5-20 拓展模型5-3,使得仓库中除装饰品外还储存小摆设和小机具。顾客的到达方式和以前一样,但是现在每个顾客对装饰品、小摆设和小机具都有需求。对装饰品的需求和以前一样,对小摆设的需求服从POIS(1.9),对小机具的需求为POIS(2.3)。假设一个顾客对一种产品的需求与他对其它两种产品的需求是独立的。仍然有一个库存检查员在每天一开始的时候到达,但是现在必须检查三种产品的库存并按各自的(s,S)订货策略订货。对于装饰品, (s,S) = (20,40),和以前一样;对于小摆设, (s,S) = (15,35),对于小机具,(s,S) = (25,45)。装饰品的交货延迟不变,仍为UNIF(0.5,1.0),小摆设的交货延迟是UNIF(0.4,0.8),小机具的是UNIF(0.8,1.7)。小摆设和小机具的订货费用(包括固定的和可变的)、储存费用和缺货费用与装饰品相同。运行仿真,运行时间和模型5-3一样(即可以修改终止时间以避免在时刻120处出现无用的库存检查)。求取每天的总成本,以及每种产品各自的储存和缺货成本。 5-21 在习题5-20中,假设三种产品的供应商合并,并同意消除在同一天订货中的多重固定费用,也即,不管Bucky在一天中订了什么产品,他只需要交一共32美元的固定费用,而不是每种不同产品各交32美元。(如果没有订货,也就不需交固定费用)。根据本题的情况修改习题5-20的模型。从选取更好的s 和S值的角度出发,你认为这种费用结构对Bucky 有什么激励(见习题6-13和6-14)? 1 准确(几乎准确)地说,其概率为� EMBED Equation.3 ���。实际上,这个数值是在给定第一个时间段中有顾客到达且最后一个到达时刻为第29分钟的条件下,第二个时间段内没有实体到达的条件概率。但这并不是我们所需要的,我们需要的是第二个时间段内没有顾客到达的无条件概率。这个是可以求出来的,但比较复杂。但是容易得出这个概率的一个下界,可由“第一个顾客在时间0后到达、由均值为20的指数分布生成、并在第60分钟后发生”这一事件的概率来估计。这是处理第二个时间段内没有顾客到达的一种方法(不是唯一的),其概率为� EMBED Equation.3 ���。因此,按照那个不正确的方法,至少有5%的可能性在第二个时间段中没有实体到达。现在,回到原文,看下一个句子,并且注意第二个脚注。 2第二个时间段没有实体到达的概率应该为� EMBED Equation.3 ���。 3正如Car M.Harris最近指出的,“排队(queueing)”显然是英语中唯一一个有五个(或以上)连续元音字母的单词,见Gass and Gross(2000)。 _1178084142.unknown _1178084375.unknown _1178051433.unknown
本文档为【arena中文教程arena中文教程第5章】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_186928
暂无简介~
格式:doc
大小:216KB
软件:Word
页数:67
分类:
上传时间:2018-09-06
浏览量:129