一、数据重构
前文数据不能直接用来进行调度,必须将其重新处理得到调度数据,根据内燃机加工特点建立模型,工序组非完全柔性车间调度问题。
已知n个零件产品,每个零件产品需要一定数量毛坯件分别独立加工,则每个零件需要进行的工序为所有毛坯件加工工序数之和。而每个毛坯件的加工各工序(工序组内部)有先后顺序约束,毛坯件之间没有先后约束,即工序组柔性加工。每个工序在一个机器上加工,个别机器存在并行相同机器,可以进行替代。因此需要的数据主要有:零件-工序(位置时间)表、装配任务表。目标为零件平均通过时间最短和总的makespan最短。
二、编程实现
1.智能算法
如遗传算法,编码阶段实现零件顺序编码,其需要包括不同毛坯件的顺序或者只对零件编码不包括毛坯件,毛坯件单独进行排序优化;然后注意并行机器的影响,其主要影响并行毛坯件或其他零件的毛坯件,在机器选择时进行判定较早结束的机器,看下论文中轮旋的方式选择机器;其次注意阻塞问题,流水工序中,机器使用不足时前面毛坯件被阻塞,优化阻塞时间(优化投入时间)来减少通过时间——阻塞时间的计算。
2.强化学习
如深度强化学习,状态的设置,包括剩余零件数量、机器闲置时间、设备利用率、每个零件的加功率、方差等等,根据文献中的方法进行优化,也是一部分关键;动作设置,每台机器对毛坯件的选择;奖励设置,完工率,目标阻塞时间与完工时间的设置;更新方式设置,如何更新Q表使得下次在特定状态时选择更好的动作。
3.数据处理
一般此种真实案例的数据多数以excel表格形式存储,因此在数据读取和处理上非常有必要进行学习转化。以几个简单案例来说明如何处理。
上面的截图中有三种装配件,分别是 PH80048033CB、PH80048050CBH_H和PH80040119__H1_H。其对应零件为右边的几个投入零件编号以及对应数量,如PH80048033CB对应PA80040194和PH80040042Z,数量分别为1和1,装配时间为20。则进行读取该excel时,可用以下代码:
import xlrd
xl = xlrd.open_workbook(r"G:\gas_engine\assembly_process.xls") # 获得数据位置
table = xl.sheets()[0]
rows = table.nrows
assemblys = {} # # 装配件,以字典形式存贮
for i in range(rows):
row_v = table.row_values(i)
if i == 0 and row_v[9] != '': # 此处避免读入空值
assemblys[(row_v[0], row_v[3], row_v[5])] = [(row_v[9], row_v[11])]
machine, time = row_v[3], row_v[5]
else:
if table.row_values(i)[0] == table.row_values(i-1)[0] and row_v[9] != '': # 是同一装配件
machine_, time_ = machine, time
assemblys[(row_v[0], machine, time)].append((row_v[9], row_v[11]))
else:
if row_v[9] != '':
assemblys[(row_v[0], row_v[3], row_v[5])] = [(row_v[9], row_v[11])]
machine, time = row_v[3], row_v[5]
下面的数据和上面相反,则需要进行其他逻辑转换:
该零件的几道工序已给出,同样使用字典形式:
job_all = {} # 零件任务集合,字典形式{任务:工序列表}
# no_l = []
for j in range(len(ope_num)): # 任务遍历len(ope_num)=len(no_before)
if j == 0:
job_all[no_before[j]] = values[:ope_num[j]] # 第一个零件的工序集合为所有集合的前序号个
# no_l.append(l[:ope_num[j]])
else:
job_all[no_before[j]] = values[sum(ope_num[:j]):sum(ope_num[:j+1])] # 之后的工序数计算方式
# no_l.append(l[sum(ope_num[:j]):sum(ope_num[:j+1])])
这样,读入数据可以避免读入空键,同时保证值被录入。