1

新的 python 用户在这里并第一次在这个伟大的网站上发帖。我一直无法找到我的问题的答案,所以希望它是独一无二的。

使用 simpy 我正在尝试创建一个火车地铁/地铁模拟,并定期在系统中内置故障和维修。这些故障不仅发生在火车上,也发生在轨道部分和平台上的信号上。我已经阅读并应用了官方的 Machine Shop 示例(您可以在附加的代码中看到相似之处),因此设法通过中断其“行程时间”来模拟火车的随机故障和维修。

但是,我还没有弄清楚如何对火车所遵循的路线上的信号故障进行建模。我目前只是指定从 A 到 B 的旅行时间,这确实会中断,但只是由于火车故障。

是否可以将每个行程定义为自己的流程,即 A_to_B 和 B_to_C 部分的单独流程,并将平台单独定义为 pA、pB 和 pC。每个都有一个资源(一次只允许一列火车),并为这些部分和平台流程合并随机故障和维修?我还可能需要在两个平台之间有几个部分,其中任何一个都可能会失败。

任何帮助将不胜感激。

到目前为止,这是我的代码:

import random
import simpy
import numpy

RANDOM_SEED = 1234

T_MEAN_A = 240.0 # mean journey time
T_MEAN_EXPO_A = 1/T_MEAN_A # for exponential distribution

T_MEAN_B = 240.0 # mean journey time
T_MEAN_EXPO_B = 1/T_MEAN_B # for exponential distribution

DWELL_TIME = 30.0 # amount of time train sits at platform for passengers
DWELL_TIME_EXPO = 1/DWELL_TIME

MTTF = 3600.0  # mean time to failure (seconds)
TTF_MEAN = 1/MTTF # for exponential distribution

REPAIR_TIME = 240.0
REPAIR_TIME_EXPO = 1/REPAIR_TIME

NUM_TRAINS = 1
SIM_TIME_DAYS = 100
SIM_TIME = 3600 * 18 * SIM_TIME_DAYS
SIM_TIME_HOURS = SIM_TIME/3600


# Defining the times for processes
def A_B(): # returns processing time for journey A to B
    return random.expovariate(T_MEAN_EXPO_A) + random.expovariate(DWELL_TIME_EXPO)

def B_C(): # returns processing time for journey B to C
    return random.expovariate(T_MEAN_EXPO_B) + random.expovariate(DWELL_TIME_EXPO)

def time_to_failure(): # returns time until next failure
    return random.expovariate(TTF_MEAN)


# Defining the train
class Train(object):

    def __init__(self, env, name, repair):
        self.env = env
        self.name = name
        self.trips_complete = 0
        self.broken = False

    # Start "travelling" and "break_train" processes for the train
        self.process = env.process(self.running(repair))
        env.process(self.break_train())

    def running(self, repair):
        while True:
        # start trip A_B
            done_in = A_B()
            while done_in:
                try:
                    # going on the trip
                    start = self.env.now
                    yield self.env.timeout(done_in)
                    done_in = 0 # Set to 0 to exit while loop

                except simpy.Interrupt:
                    self.broken = True
                    done_in -= self.env.now - start # How much time left?
                    with repair.request(priority = 1) as req:
                        yield req
                        yield self.env.timeout(random.expovariate(REPAIR_TIME_EXPO))
                    self.broken = False
        # Trip is finished
            self.trips_complete += 1

        # start trip B_C
            done_in = B_C()
            while done_in:
                try:
                    # going on the trip
                    start = self.env.now
                    yield self.env.timeout(done_in)
                    done_in = 0 # Set to 0 to exit while loop

                except simpy.Interrupt:
                    self.broken = True
                    done_in -= self.env.now - start # How much time left?
                    with repair.request(priority = 1) as req:
                        yield req
                        yield self.env.timeout(random.expovariate(REPAIR_TIME_EXPO))
                    self.broken = False
        # Trip is finished
            self.trips_complete += 1


    # Defining the failure      
    def break_train(self):
        while True:
            yield self.env.timeout(time_to_failure())
            if not self.broken:
            # Only break the train if it is currently working
                self.process.interrupt()


# Setup and start the simulation
print('Train trip simulator')
random.seed(RANDOM_SEED) # Helps with reproduction

# Create an environment and start setup process
env = simpy.Environment()
repair = simpy.PreemptiveResource(env, capacity = 1)
trains = [Train(env, 'Train %d' % i, repair)
    for i in range(NUM_TRAINS)]

# Execute
env.run(until = SIM_TIME)


# Analysis
trips = []
print('Train trips after %s hours of simulation' % SIM_TIME_HOURS)
for train in trains:
    print('%s completed %d trips.' % (train.name, train.trips_complete))
    trips.append(train.trips_complete)

mean_trips = numpy.mean(trips)
std_trips = numpy.std(trips)
print "mean trips: %d" % mean_trips
print "standard deviation trips: %d" % std_trips
4

1 回答 1

1

看起来您正在使用 Python 2,这有点不幸,因为 Python 3.3 及更高版本为您提供了更多使用 Python 生成器的灵活性。但是您的问题应该可以在 Python 2 中解决。

您可以在流程中使用子流程:

def sub(env):
    print('I am a sub process')
    yield env.timeout(1)
    # return 23  # Only works in py3.3 and above
    env.exit(23)  # Workaround for older python versions

def main(env):
    print('I am the main process')
    retval = yield env.process(sub(env))
    print('Sub returned', retval)

如您所见,您可以使用由 正常事件Process返回的实例。Environment.process()您甚至可以在子进程中使用返回值。

如果您使用 Python 3.3 或更高版本,则不必显式启动新的子进程,但可以将sub()其用作子例程,只需转发它产生的事件:

def sub(env):
    print('I am a sub routine')
    yield env.timeout(1)
    return 23

def main(env):
    print('I am the main process')
    retval = yield from sub(env)
    print('Sub returned', retval)

您还可以将信号建模为可供故障过程或火车使用的资源。如果故障进程首先请求信号,则列车必须在信号前等待,直到故障进程释放信号资源。如果火车已经通过信号(因此有资源),信号就不会中断。我认为这不是问题,因为火车无论如何都不能停下来。如果它应该是一个问题,只需使用 PreemptiveResource。

我希望这有帮助。欢迎加入我们的邮件列表以进行更多讨论。

于 2015-02-03T20:39:26.690 回答