1

ここに新しい python ユーザーがいて、この素晴らしいウェブサイトに最初に投稿します。私の質問に対する答えを見つけることができなかったので、それがユニークであることを願っています。

simpy を使用して、システムに定期的に組み込まれた障害と修理を備えた電車の地下鉄/地下鉄シミュレーションを作成しようとしています。これらの障害は、列車だけでなく、線路の一部やプラットホームの信号機にも発生します。私は公式の Machine Shop の例 (添付のコードに似ていることがわかります) を読んで適用し、その「移動時間」を中断することで、列車の偶発的な故障と修理をモデル化することができました。

しかし、列車が通るルートの信号機の故障をモデル化する方法がわかりませんでした。私は現在、A から B への旅行の時間を指定しているだけです。これは中断されますが、列車の故障によるものです。

各トリップを独自のプロセスとして定義することは可能ですか。つまり、セクション A_to_B および B_to_C に対して個別のプロセスを定義し、プラットフォームを pA、pB、および pC として個別に定義することは可能ですか。それぞれに単一のリソースがあり (一度に 1 つの列車のみを許可する)、これらのセクションおよびプラットフォーム プロセスのランダムな障害と修理を組み込むには? また、2 つのプラットフォーム間にいくつかのセクションを設ける必要があり、そのいずれかで障害が発生する可能性があります。

どんな助けでも大歓迎です。

これまでの私のコードは次のとおりです。

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 に答える