如何使用Simpy使用缓冲区对2台机器进行仿真?

发布于 2025-01-19 16:01:19 字数 5113 浏览 2 评论 0原文

我是模拟的新手,并且正在浏览小型文档。我有点想起它,但似乎真的无法掌握如何翻译我要模拟的生产线。

我正在尝试使用M数量的机器和M-1数量的缓冲区来模拟生产线。

这些机器基本上的工作也相同:

  • 每个状态的速度s的过程单元
  • 在该状态下的随机分布,在该状态下的时间
  • 是否有缓冲区的饥饿/阻塞?

缓冲区的所有工作都相同:

  • 从上一个机器接收单元
  • 从下一个机器
  • 容量(t)=容量(t -1) +(输入上一个机器) - (输出下一步) 机器)
  • 容量(t)< =最大容量

现在我知道模拟的第一步是婴儿步骤,因此我需要先制作一个简单的模型。我想要创建的然后使用小合理的是一台2机器和1个具有固定处理速度,故障率和维护速度的缓冲系统:

  1. 单位的无限容量将输送到机器1。
  2. 速度S的机器1流程,f MINUTES后失败。并在R分钟后修复。如果缓冲区已满,则机器1停止。
  3. 缓冲区被机器1填充,并用机器2倒空。最大容量。
  4. 机器2在最小值(速度为s,容量缓冲区)后发生,在F分钟后失败,并在R分钟后修复。如果缓冲区为空,则将机器2停止。
  5. 机器2后无限的缓冲区容量。

编辑:我从@michael收到的答案非常好,我尝试在失败和维护方面玩耍。该机器似乎失败和维修,但在失败时间的倍数(我需要修复的时间)上一直失败。我使用的代码如下:

# Machine 1
speed_1 = 2          # Avg. processing time of Machine 1 in minutes
# speed_1_stdev = 0.6  # St. dev. of processing time of Machine 1
MTTF_1 = 10          # Mean time to failure Machine 1
# fail_1 = 1/MTTF_1    # Parameter for exp. distribution
repair_1 = 3         # Time it takes to repair Machine 1

# Machine 2
speed_2 = 3          # Processing time of Machine 2 in minutes
# speed_2_stdev = 0.6  # St. dev. of processing time of Machine 2
MTTF_2 = 7           # Mean time to failure Machine 1
# fail_2 = 1/MTTF_2    # Parameter for exp. distribution
repair_2 = 4         # Time it takes to repair Machine 2

# Simulation time
time = 120           # Sim time in minutes

#---------------------------------------------------------------------
# Class setup for a Machine
class Machine(object):
    """
    A machine produces units at a fixed processing speed, 
    takes units from a store before and puts units into a store after.

    Machine has a *name*, a processing speed *speed*, a preceeding buffer *in_q*,
    and a proceeding buffer *out_q*.
    
    Next steps: 
    - Machine produces units at distributed processing speeds.
    - A machine fails at fixed intervals and is repaired at a fixed time.
    - Failure and repair times are distributed.
    """
    def __init__(self, env, name, in_q, out_q, speed, mttf, repair):
        self.env = env
        self.name = name
        self.in_q = in_q
        self.out_q = out_q
        self.speed = speed
        self.mttf = mttf
        self.repair = repair
        self.broken = False

        # Start the producing process
        self.process = env.process(self.produce())
        # Start the failure process
        env.process(self.fail_machine())
    
    def produce(self):
        """
        Produce parts as long as the simulation runs.
        """
        while True:
            part = yield self.in_q.get()
            try:
                # If want to see time {self.env.now:.2f} 
                print(f'{self.name} has got a part')

                yield env.timeout(self.speed)
                if len(self.out_q.items) < self.out_q.capacity:
                    print(f'{self.name} finish a part next buffer has {len(self.out_q.items)} and capacity of {self.out_q.capacity}')
                else:
                    print(f'{self.env.now:.2f}  {self.name} output buffer full!!!')

                yield self.out_q.put(part)
                print(f'{self.name} pushed part to next buffer')
            
            except simpy.Interrupt:
                self.broken = True
                yield self.env.timeout(self.repair)
                print(f'{self.env.now:.2f} {self.name} is in fixed')
                self.broken = False
        
    def fail_machine(self):
        """
        The machine is prone to break down every now and then.
        """
        while True:
            yield self.env.timeout(self.mttf)
            print(f'{self.env.now:.2f} {self.name} is in failure.')
            if not self.broken:
                # Machine only fails if currently working.
                self.process.interrupt(self.mttf)
#---------------------------------------------------------------------
# Generating the arrival of parts in the entry buffer to be used by machine 1
def gen_arrivals(env, entry_buffer):
    """
    Start the process for each part by putting
    the part in the starting buffer
    """
    while True:
        yield env.timeout(random.uniform(0,0.001))
        # print(f'{env.now:.2f} part has arrived')
        part = object() # Too lazy to make a real part class, also isn't necessary

        yield entry_buffer.put(part)

#---------------------------------------------------------------------
# Create environment and start the setup process
env = simpy.Environment()
bufferStart = simpy.Store(env)  # Buffer with unlimited capacity
buffer1 = simpy.Store(env, capacity = 8) # Buffer between machines with limited capacity
bufferEnd = simpy.Store(env)  # Last buffer with unlimited capacity

# The machines __init__ starts the machine process so no env.process() is needed here
machine_1 = Machine(env, 'Machine 1', bufferStart, buffer1, speed_1, MTTF_1, repair_1)
machine_2 = Machine(env, 'Machine 2', buffer1, bufferEnd, speed_2, MTTF_2, repair_2)

env.process(gen_arrivals(env, bufferStart))

# Execute
env.run(until = time)

I am new to simulation and am going through the simpy documentation. I kind of get the gist of it but cannot really seem to grasp how to translate the production line that I want to simulate.

I am trying to simulate a production line with m number of machines and m-1 number of buffers.

The machines basically work the same:

  • Processes units at speed s per state
  • random distribution of states and time in said state
  • Is there starvation/blockage from the buffers?

The buffers all work the same:

  • Receives units from previous machine
  • Loses units from next machine
  • capacity(t) = capacity(t-1) + (input previous machine) - (output next
    machine)
  • Capacity(t) <= Max capacity

Now I get that the first steps of simulation are baby steps so I need to make a simple model first. What I am looking to create then using simpy is a 2 machine and 1 buffer system with fixed processing speeds, failure rate and maintenance speeds:

  1. An unlimited capacity of units is delivered to machine 1.
  2. Machine 1 processes at speed s, fails after f minutes and is repaired after r minutes. If buffer is full then Machine 1 stops.
  3. Buffer gets filled by Machine 1 and emptied by Machine 2. There is a max capacity.
  4. Machine 2 processes at min(speed s, capacity buffer) fails after f minutes and is repaired after r minutes. If buffer is empty then Machine 2 stops.
  5. Unlimited buffer capacity after Machine 2.

EDIT: The answer I received from @Michael works very well, I tried playing around with failures and maintenance. The machine seems to fail and repaired, but keeps failing at multiples of the time to failure (which I need to fix). The code I am using is as follows:

# Machine 1
speed_1 = 2          # Avg. processing time of Machine 1 in minutes
# speed_1_stdev = 0.6  # St. dev. of processing time of Machine 1
MTTF_1 = 10          # Mean time to failure Machine 1
# fail_1 = 1/MTTF_1    # Parameter for exp. distribution
repair_1 = 3         # Time it takes to repair Machine 1

# Machine 2
speed_2 = 3          # Processing time of Machine 2 in minutes
# speed_2_stdev = 0.6  # St. dev. of processing time of Machine 2
MTTF_2 = 7           # Mean time to failure Machine 1
# fail_2 = 1/MTTF_2    # Parameter for exp. distribution
repair_2 = 4         # Time it takes to repair Machine 2

# Simulation time
time = 120           # Sim time in minutes

#---------------------------------------------------------------------
# Class setup for a Machine
class Machine(object):
    """
    A machine produces units at a fixed processing speed, 
    takes units from a store before and puts units into a store after.

    Machine has a *name*, a processing speed *speed*, a preceeding buffer *in_q*,
    and a proceeding buffer *out_q*.
    
    Next steps: 
    - Machine produces units at distributed processing speeds.
    - A machine fails at fixed intervals and is repaired at a fixed time.
    - Failure and repair times are distributed.
    """
    def __init__(self, env, name, in_q, out_q, speed, mttf, repair):
        self.env = env
        self.name = name
        self.in_q = in_q
        self.out_q = out_q
        self.speed = speed
        self.mttf = mttf
        self.repair = repair
        self.broken = False

        # Start the producing process
        self.process = env.process(self.produce())
        # Start the failure process
        env.process(self.fail_machine())
    
    def produce(self):
        """
        Produce parts as long as the simulation runs.
        """
        while True:
            part = yield self.in_q.get()
            try:
                # If want to see time {self.env.now:.2f} 
                print(f'{self.name} has got a part')

                yield env.timeout(self.speed)
                if len(self.out_q.items) < self.out_q.capacity:
                    print(f'{self.name} finish a part next buffer has {len(self.out_q.items)} and capacity of {self.out_q.capacity}')
                else:
                    print(f'{self.env.now:.2f}  {self.name} output buffer full!!!')

                yield self.out_q.put(part)
                print(f'{self.name} pushed part to next buffer')
            
            except simpy.Interrupt:
                self.broken = True
                yield self.env.timeout(self.repair)
                print(f'{self.env.now:.2f} {self.name} is in fixed')
                self.broken = False
        
    def fail_machine(self):
        """
        The machine is prone to break down every now and then.
        """
        while True:
            yield self.env.timeout(self.mttf)
            print(f'{self.env.now:.2f} {self.name} is in failure.')
            if not self.broken:
                # Machine only fails if currently working.
                self.process.interrupt(self.mttf)
#---------------------------------------------------------------------
# Generating the arrival of parts in the entry buffer to be used by machine 1
def gen_arrivals(env, entry_buffer):
    """
    Start the process for each part by putting
    the part in the starting buffer
    """
    while True:
        yield env.timeout(random.uniform(0,0.001))
        # print(f'{env.now:.2f} part has arrived')
        part = object() # Too lazy to make a real part class, also isn't necessary

        yield entry_buffer.put(part)

#---------------------------------------------------------------------
# Create environment and start the setup process
env = simpy.Environment()
bufferStart = simpy.Store(env)  # Buffer with unlimited capacity
buffer1 = simpy.Store(env, capacity = 8) # Buffer between machines with limited capacity
bufferEnd = simpy.Store(env)  # Last buffer with unlimited capacity

# The machines __init__ starts the machine process so no env.process() is needed here
machine_1 = Machine(env, 'Machine 1', bufferStart, buffer1, speed_1, MTTF_1, repair_1)
machine_2 = Machine(env, 'Machine 2', buffer1, bufferEnd, speed_2, MTTF_2, repair_2)

env.process(gen_arrivals(env, bufferStart))

# Execute
env.run(until = time)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梨涡少年 2025-01-26 16:01:19

对我的工作感到厌倦,所以我做了一些小更改来修复您的代码。我认为它甚至有效。最后要注意的是,不止一台机器可以使用相同的缓冲区。因此一组机器可以处理同一个缓冲区。这就是我所做的,而不是使用 simpy.resurce 作为资源池

import simpy
import random

speed_1 = 3          # Avg. processing time of Machine 1 in minutes
speed_2 = 4          # Processing time of Machine 2 in minutes
time = 120           # Sim time in minutes


# Class setup for Machine 1 
# This needs to be done as there are varying processing speeds
class Machine(object):
    """
    A machine produces units at a fixed processing speed, 
    takes units from a store before and puts units into a store after.

    Machine has a *name*
    Next steps: 
    - Machine produces units at distributed processing speeds.
    - A machine fails at fixed intervals and is repaired at a fixed time.
    - Failure and repair times are distributed.
    
    """
    def __init__(self, env, name, in_q, out_q, speed):
        self.env = env
        self.name = name
        self.in_q = in_q
        self.out_q = out_q
        self.speed = speed

        # Start the producing process
        self.process = env.process(self.produce())
    
    def produce(self):
        """
        Produce parts as long as the simulation runs.
        
        """
        while True:
            part = yield self.in_q.get()
            print(f'{self.env.now:.2f} Machine {self.name} has got a part')
            
            yield env.timeout(self.speed)
            print(f'{self.env.now:.2f} Machine {self.name} finish a part next q has {len(self.out_q.items)} and capacit of {self.out_q.capacity}')

            yield self.out_q.put(part)
            print(f'{self.env.now:.2f} Machine {self.name} pushed part to next buffer')

def gen_arrivals(env, entry_buffer):
    """
    start the process for each part by putting
    the part in the starting buffer
    """

    while True:

        yield env.timeout(random.uniform(1,4))
        print(f'{env.now:.2f} part has arrived')
        part = object() # too lazy to make a real part class

        yield entry_buffer.put(part)




# Create environment and start the setup process
env = simpy.Environment()
bufferStart = simpy.Store(env)  # Buffer with unlimited capacity
buffer1 = simpy.Store(env, capacity = 6) # Buffer between machines with limited capacity
bufferEnd = simpy.Store(env)  # Last buffer with unlimited capacity

# the machines __init__ starts the machine process so no env.process() is needed here
machine_1 = Machine(env, 'Machine 1', bufferStart, buffer1, speed_1)
machine_2 = Machine(env, 'Machine 2', buffer1, bufferEnd, speed_2)
#machine_3 = Machine(env, 'Machine 3', buffer1, bufferEnd, speed_2)

env.process(gen_arrivals(env, bufferStart))


# Execute
env.run(until = time)

Got bored of my work, so I made some small changes to fix your code. I think it even works. One final note, more then one machine can use the same buffer. so a pool of machines can process out of the same one buffer. This is what I do instead of using a simpy.resurce for a resource pool

import simpy
import random

speed_1 = 3          # Avg. processing time of Machine 1 in minutes
speed_2 = 4          # Processing time of Machine 2 in minutes
time = 120           # Sim time in minutes


# Class setup for Machine 1 
# This needs to be done as there are varying processing speeds
class Machine(object):
    """
    A machine produces units at a fixed processing speed, 
    takes units from a store before and puts units into a store after.

    Machine has a *name*
    Next steps: 
    - Machine produces units at distributed processing speeds.
    - A machine fails at fixed intervals and is repaired at a fixed time.
    - Failure and repair times are distributed.
    
    """
    def __init__(self, env, name, in_q, out_q, speed):
        self.env = env
        self.name = name
        self.in_q = in_q
        self.out_q = out_q
        self.speed = speed

        # Start the producing process
        self.process = env.process(self.produce())
    
    def produce(self):
        """
        Produce parts as long as the simulation runs.
        
        """
        while True:
            part = yield self.in_q.get()
            print(f'{self.env.now:.2f} Machine {self.name} has got a part')
            
            yield env.timeout(self.speed)
            print(f'{self.env.now:.2f} Machine {self.name} finish a part next q has {len(self.out_q.items)} and capacit of {self.out_q.capacity}')

            yield self.out_q.put(part)
            print(f'{self.env.now:.2f} Machine {self.name} pushed part to next buffer')

def gen_arrivals(env, entry_buffer):
    """
    start the process for each part by putting
    the part in the starting buffer
    """

    while True:

        yield env.timeout(random.uniform(1,4))
        print(f'{env.now:.2f} part has arrived')
        part = object() # too lazy to make a real part class

        yield entry_buffer.put(part)




# Create environment and start the setup process
env = simpy.Environment()
bufferStart = simpy.Store(env)  # Buffer with unlimited capacity
buffer1 = simpy.Store(env, capacity = 6) # Buffer between machines with limited capacity
bufferEnd = simpy.Store(env)  # Last buffer with unlimited capacity

# the machines __init__ starts the machine process so no env.process() is needed here
machine_1 = Machine(env, 'Machine 1', bufferStart, buffer1, speed_1)
machine_2 = Machine(env, 'Machine 2', buffer1, bufferEnd, speed_2)
#machine_3 = Machine(env, 'Machine 3', buffer1, bufferEnd, speed_2)

env.process(gen_arrivals(env, bufferStart))


# Execute
env.run(until = time)
和我恋爱吧 2025-01-26 16:01:19

我将simmpy.store用于缓冲区。您可以为商店设置最大容量,我认为默认值是无限的。当您进行收益my_store.put()时,如果商店处于容量状态,它将阻止。另外,当您进行收益my_store.get()时,如果商店为空,它将阻止它。

您需要做一个机器课。对于第一个版本,我会跳过故障。该机器应具有一个无限循环的过程,该过程从其输入缓冲区中进行get(),延迟一些时间(forad env.timeout()),然后进行put()将零件放入下一个机器的输入缓冲区中。第一个版本应该看起来像:将到达的零件产生到计算机1输入缓冲区,一个机器1从其输入缓冲区拉(get(get())到机器的2输入缓冲区,一个机器1从其输入缓冲区和推动(put())将(get(get())拉到出口缓冲区缓冲区的机器2。 So thats 1 generate arrivals, 2 machines (can be the same class) and 3 simpy.Store s

give it a try.如果您仍然需要示例代码,我将在本周末尝试使用。今天和下一步都有真正的工作要做。

祝你好运

I use simmpy.Store for buffers. you can set a max capacity for a store, I think the default is infinite. When you do a yield my_store.put() it will block if the store is at capacity. Also when you do a yield my_store.get(), it will block if the store is empty.

You will need to make a machine class. for the first version I would skip the breakdown. The machine should have a process with a infinite loop that does a get() from its input buffer, delay some time (yield env.timeout()) and then does a put() to put the part into the next machine's input buffer. The first version should look like: a process that generate arriving parts that are put into machine 1 input buffer, a machine 1 that pulls (get()) from its input buffer and pushes (put()) to machine's 2 input buffer, a machine 2 that pulls (get()) from its input buffer and pushes (put()) to a exit buffer buffer. So thats 1 generate arrivals, 2 machines (can be the same class) and 3 simpy.Store s

give it a try. If you still need a example code, I try to to it this weekend. Got real job stuff to do today and next.

good luck

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文