网格/仓库布局上离散事件模拟的可视化
Posted
技术标签:
【中文标题】网格/仓库布局上离散事件模拟的可视化【英文标题】:Visualization of a discrete-event simulation on a grid / warehouse layout 【发布时间】:2017-09-20 18:44:17 【问题描述】:我需要模拟一个仓库,其中有几辆自动驾驶汽车按照简单的优先级规则在给定布局上行驶。据我了解,这个问题可以通过离散事件模拟 (DES) 轻松解决,我会为此使用 SimPy。
我看到的问题是,我似乎很难想象这些车辆的实际轨迹和相互作用。当然,我可以记录所有时间段内所有车辆的所有位置,但我该如何继续创建可视化?
最愚蠢的方法是创建一百万张图片,但必须有更好的方法。是否有任何库或工具可以通过在背景前移动符号来可视化网格上对象的移动?
另一种选择是将基于代理的方法与AnyLogic 之类的软件一起使用,但这对我来说似乎更复杂,我想应用 DES 方法,最好使用开源软件。
【问题讨论】:
请注意,要求库或工具的建议被明确表示为结束您的问题的标准。也就是说,Simio、Arena 或 ExtendSim 等商业 DES 产品都提供动画/可视化功能。坏消息是它们很贵。可能的一线希望是其中一些可随时用于学术用途。 感谢您的澄清。如果不在 SO 上,我不确定如何以及在哪里获得有关我的问题的帮助。您会在哪里问或我需要如何改写我的问题? 【参考方案1】:我建议查看 tkinter 库。我们使用它来完成所有简单的可视化。
这是一个可以实现的动画的非常基本的例子,请原谅戏剧性的镜头:https://www.youtube.com/watch?v=xnZQ0f--Ink
这里是大致描述您在上面看到的内容的源代码:https://github.com/harrymunro/Simulations/blob/master/termini_simulation_animation.py
这里是动画组件的复制粘贴:
################ SET UP ANIMATION CANVAS #################
class Train:
def __init__(self, canvas, x1, y1, x2, y2, tag):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.canvas = canvas
self.train = canvas.create_rectangle(self.x1, self.y1, self.x2, self.y2, fill="red", tags = tag)
self.train_number = canvas.create_text(((self.x2 - self.x1)/2 + self.x1), ((self.y2 - self.y1)/2 + self.y1), text = tag)
self.canvas.update()
def move_train(self, deltax, deltay):
self.canvas.move(self.train, deltax, deltay)
self.canvas.move(self.train_number, deltax, deltay)
self.canvas.update()
def remove_train(self):
self.canvas.delete(self.train)
self.canvas.delete(self.train_number)
self.canvas.update()
class Clock:
def __init__(self, canvas, x1, y1, x2, y2, tag):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.canvas = canvas
self.train = canvas.create_rectangle(self.x1, self.y1, self.x2, self.y2, fill="#fff")
self.time = canvas.create_text(((self.x2 - self.x1)/2 + self.x1), ((self.y2 - self.y1)/2 + self.y1), text = "Time = "+str(tag)+"s")
self.canvas.update()
def tick(self, tag):
self.canvas.delete(self.time)
self.time = canvas.create_text(((self.x2 - self.x1)/2 + self.x1), ((self.y2 - self.y1)/2 + self.y1), text = "Time = "+str(tag)+"s")
self.canvas.update()
if show_animation == True:
animation = Tk()
#bitmap = BitmapImage(file="uxbridge.bmp")
im = PhotoImage(file="uxbridge_resized.gif")
canvas = Canvas(animation, width = 800, height = 400)
canvas.create_image(0,0, anchor=NW, image=im)
animation.title("Uxbridge Termini Simulation")
canvas.pack()
#### matplotlib plots
if show_animation == True and hide_plots == False:
f = plt.Figure(figsize=(5,4), dpi=100)
a1 = f.add_subplot(221) # mean headway
a2 = f.add_subplot(222) # TPH meter
a3 = f.add_subplot(223) # headway distribution
a4 = f.add_subplot(224) # train count
a1.plot()
a2.plot()
a3.plot()
a4.plot()
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
dataPlot = FigureCanvasTkAgg(f, master=animation)
dataPlot.show()
dataPlot.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
f.tight_layout()
canvas.pack()
# platforms
if show_animation == True:
canvas.create_rectangle(50, 100, 200, 150, fill = "yellow")
canvas.create_rectangle(50, 200, 200, 250, fill = "yellow")
canvas.create_line(50, 75, 200, 75, fill="green", width=3) # platform 4
canvas.create_line(50, 175, 200, 175, fill="green", width=3) # platform 2/3
canvas.create_line(50, 275, 200, 275, fill="green", width=3) # platform 1
canvas.create_text(125, 110, text = "Platform 4")
canvas.create_text(125, 140, text = "Platform 3")
canvas.create_text(125, 210, text = "Platform 2")
canvas.create_text(125, 240, text = "Platform 1")
# track
canvas.create_line(200, 75, 650, 75, fill="green", width=3) # platform 4 run out
canvas.create_line(200, 175, 650, 175, fill="green", width=3) # platform 2/3 run in
canvas.create_line(300, 175, 400, 75, fill="green", width=3)
canvas.create_line(450, 75, 600, 175, fill="green", width=3)
canvas.create_line(450, 175, 600, 75, fill="green", width=3)
canvas.create_line(200, 275, 300, 275, fill="green", width=3)
canvas.create_line(300, 275, 400, 175, fill="green", width=3)
############ END OF CANVAS #################
【讨论】:
【参考方案2】:如果动画应该是 2D 的,您可以使用 Pygame 库。我用它做了一个简单的模拟动画,效果很好。请注意,您需要使用线程,否则您的窗口将在几秒钟后冻结。这个简单的方法为每个到达的客户绘制一个红色圆圈,并在为客户服务时将其绘制为绿色。
def draw(env, timelist):
gameDisplay.fill(white)
start = time.clock()
kdnr = 0
kdaktuell = -1
kdstart = -10
while True:
timer = (time.clock() - startzeit)
if timer > 15: #simulation for 15 sec
break
# incoming customers
if kdnr < len(timelist):
if timelist[kdnr] <= timer:
pygame.draw.circle(gameDisplay,red,(50+30*kdnr,400),10)
print('Customer '+str(kdnr+1)+ ' arrived in minute: ' + str(timelist[kdnr]))
kdnr = kdnr + 1
# served customers
if (kdstart+3) <= timer:
kdaktuell = kdaktuell + 1
kdstart = time
pygame.draw.circle(gameDisplay,green,(50+30*kdaktuell,400),10)
print('Customer '+str(kdaktuell+1)+ ' gets served.')
pygame.display.update()
【讨论】:
函数draw中没有使用env。【参考方案3】:我会收集所有需要的数据并将它们存储在某个地方(文件、HDF5、sql...)。稍后(或并行),您可以可视化该数据。要么使用 matplotlib 生成大量图像,要么使用 D3.js 做一些更花哨的事情。
【讨论】:
我的问题是究竟如何我会做这个可视化部分。如果我有一个 8 小时的挂钟时间的模拟并每秒拍摄一张“照片”,那么我有 8 小时 * 60 分钟/小时 * 60 秒/分钟 * 1 MB = 28.8 GB 用于一次模拟运行的可视化。这似乎有点过分了。我正在寻找更有效的解决方案。对于这个动态问题,我还没有找到相应的 D3.js 图表选项。你能直接给我指一个吗?【参考方案4】:我发现 R 库 gganimate 可以满足我的需求。我还没有找到 Python 的等价物(可能是因为 Python 中既没有 ggplot2 也没有 animate 等价物......)
【讨论】:
【参考方案5】:对您打算用于模拟库的内容稍作改动,可以使用 salabim 而不是 simpy。它与 simpy 非常相似,但有一个动画引擎,大大简化了流程。
【讨论】:
以上是关于网格/仓库布局上离散事件模拟的可视化的主要内容,如果未能解决你的问题,请参考以下文章