本篇博客主要介绍模型建模过程,以及相应的代码和逻辑解释
从执行模型的角度来说,首先是初始化
HandlingCost := 0
PartsNo :=0
InitPartsTable --初始化表格
GASequence.delete --删除GA序列
for var i := 1 to Number_OF_Machine --与遗传算法有关,用于生成初始序列
GASequence[1, i] := i
next
InitPartsTable方法释义如下
var Rows, Lines: integer
var MachineName, BufName: string
var Machine, Buf: object
if Number_Of_Machine /= D_From_To_Chart.YDim --为整数代表True
switch messageBox("设施数目不对,请核查…", 50, 13) --数字50表示按钮组合是否取消,数字13表示带有感叹号的黄色三角形。
case 16 --1表示确定,2表示取消,16表示是,32表示否。
print "yes"
case 32
print "no"
else
print "Cancel"
end
EventController.stop --事件停止运行
end
PartsTable.delete --清空列表
for var i := 1 to Number_Of_Machine
for var j := 1 to Number_Of_Machine
if j < i --表格左下角部分
if D_From_To_Chart[j,i] <= 0 --如果左下角小于或者等于0
D_From_To_Chart[j,i] := D_From_To_Chart[i,j]; --右上角对称对应值填补到左下角
end
else
if j = i --表格对角线部分
D_From_To_Chart[j,i] := 0 --置0
else
if D_From_To_Chart[j,i] <= 0 --表格右上角部分
messageBox("距离小于等于零...",50, 13) --判断是否有误输入值,否则不干了
EventController.stop
end
end
end
next
next
for var m := 1 to Number_Of_Machine --删除之前建立的机器对象以及前置缓存区
MachineName := sprint("M", m) --MachineName = "M1" ... "M8"
if existsObject(MachineName) --判断MachineName是否存在,返回布尔值
Machine := str_to_obj(MachineName) --字符串转对象,赋给Machine,这里是删机器"M1"..."M8"
Machine.deleteObject --删除对象
end
BufName := sprint("BF", m) --BufName = "BF1"..."BF8"
if existsObject(BufName) --判断MachineName是否存在,返回布尔值
Buf := str_to_obj(BufName) --字符串转对象,赋给Buf,这里是删机器"BF1"..."BF8"
Buf.deleteObject --删除对象
end
next
Lines := 0
for var n := 1 to Number_Of_Machine
Rows := str_to_num(Omit(MachineSequence[1,n],1, 1)) --Omit函数,这里是指从MachineSequence表里从指定位置删除内容(1,1),代表删除第一个开始的一个元素,具体"M1”删除了"M",留下了“1”
MachineSequence[2, n] := Rows --把"1"..."8"放到第二列
for var p := 1 to Number_Of_Machine
if W_From_To_Chart[p, Rows] > 0 --按行扫描,只要存在搬运物料就写入表PartsTable
Lines := Lines + 1
PartsTable[1, Lines] := str_to_obj(sprint(".", location.name,".Parts")) --写模型名字
PartsTable[2, Lines] := W_From_To_Chart[p, Rows] --写模型物料量
PartsTable[3, Lines] := sprint("Parts") --写入名称"Parts"
PartsTable[5, Lines] := Rows --写入表格W_From_To横坐标,即物料源地址
PartsTable[6, Lines] := p --写入表格W_From_To纵坐标,即物料目的地址
end
next
MachineName := sprint("M", Rows) --MachineName = "M1" ... "M8"
Machine := .MaterialFlow.SingleProc.createObject(current, X_pos_init + D_From_To_Chart[Number_Of_Machine + 1, n], Y_pos_init +D_From_To_Chart[Number_Of_Machine + 2, n])
-- 创建处理过程对象(机器)指定存放位置,在D_From_To_Chart第9列和第10列存放,下面缓存对象类似
Machine.Name := MachineName --定义名字赋给机器名
Machine.ProcTime := 5 --定义处理时间
Machine.label := sprint("机器_", Rows) --设置标签
Machine.ExitCtrl := &Leave --每当机器处理完零件,零件离开触发Leave方法
BufName := sprint("BF", Rows) --BufName = "BF1"..."BF8"
Buf := .MaterialFlow.Buffer.createObject(current, X_pos_init + D_From_To_Chart[Number_Of_Machine + 1, n]-35, Y_pos_init + D_From_To_Chart[Number_Of_Machine+2, n])
-- 创建处理过程对象(前置缓存区)指定存放位置,在D_From_To_Chart第9列和第10列存放,扣去横坐标相对位移35
Buf.Name := BufName
Buf.Capacity := 5000
Buf.ProcTime := 0
.MaterialFlow.Connector.connect(Buf, Machine) --对应的前置缓存区和机器相连
next
通过上述两部初始化动作,八个前置缓存区和八个机器就已经按如下顺序放在对应的地点,并且PartsTable表格已经建立完毕,以下为部分示意图
另外,关于从至表的填写和校准工作也已经完成,也就是W_From_To_Chart表和D_From_To_Chart表已经布置和核对,MachineSequence的第一、二列也完成
初始化之后,单击运行按钮。这里便是Source对象的理解
在本模型当中,Source每间隔20s产生一个零件(物料),由于采用了序列模式,关联了PartsTable表格,所以产生的零件(物料量)的种类不同,每种类型的个数也不一样。并且对于每个具体的Parts(零件),它的源地址和目的地址设定好,当然每批同类型的零件都流向了同样的目的地,源地址也相同。
零件流通方向大致示意图如下,假设第一个加工零件,由Source的Load产生,放置于BF1前置缓存区,再经过M1机器处理,离开执行Leave方法,再流向BF2缓存区,再经过M2机器处理,最终到达Drain
关于Load方法,下面为代码和注解
var no, m: integer
var Buf: object
m := 0
no := @.getNo --获取Parts(零件)编号,比如第一个过来的零件编号是1,接下来第二个过来就编号2了,注意编号唯一,共2347
for var i := 1 to PartsTable.YDim --PartsTable.YDim = 24, 对PartsTable表行循环
if PartsNo = m and no <= PartsNo + PartsTable[2, i] --判断是否是同一批次的零件
@._From := PartsTable[5, i] --该零件源地址标记
@._to := PartsTable[6, i] --该零件目的地址标记
if no = PartsNo + PartsTable[2, i] --同批次最后一个零件到来的时候,更新下一批,结合上一个if PartsNo = m的判断
PartsNo := PartsNo + PartsTable[2, i]
end
i := PartsTable.YDim + 1 --跳出循环,值得注意下面m := m + PartsTable[2, i]会执行
end
m := m + PartsTable[2, i] --m获取每批次需要运输的零件量
next
Buf := str_to_obj(sprint("BF", @._From)) --创建当前零件流入的Buf(缓存区)
@.move(Buf) --把零件放置到缓存区
关于Leave方法,下面为代码和注解
var i, j: integer
var Machine: object
Machine := str_to_obj(sprint("M", @._To)) --创建当前零件目的地址机器
if ?.name /= Machine.Name --判断该零件的目的地属性是否就是本机床,名字相同执行else部分,名字不同执行if下面代码团
Machine := str_to_obj(sprint("BF", @._To)) --放到下一个缓存区
@.move(Machine) --移动到下一个机器
for var k := 1 to Number_Of_Machine --在MachineSequence表里面找到对应的机器的源地址和目的地对应的D_From_To_Chart的移动距离
if MachineSequence[2, k] = @._From
i := k
end
if MachineSequence[2, k] = @._To
j := k
end
next
HandlingCost := HandlingCost + D_From_To_Chart[j, i] --目标函数(注意,因为零件已经时一个个上传过来了,所以距离的累加其实默认乘以1零件数,求值方法巧妙)
else
@.move(Drain)
end
下一篇,把遗传算法运用到模型的思路捋一捋,还有代码分析过程。