8.4 应用:计算机仿真

        8.4.1 航空公司票务柜台

        本节对航空公司票务柜台进行仿真模拟。

        队列系统建模

       我们通过离散时间仿真来建模,这个仿真是一系列能显著改变系统的事件。它由时间驱动,并运行给定的时间。用户可以使用一些参数来设定系统。在这里,这些参数是

  • 系统运行的时长;
  • 柜台数量;
  • 完成一次交易的时间;
  • 顾客到来的时间分布。

        最后还要设定一些规则。

  • 顾客到来之后,自动加入到队列当中,每一个时间单位内至多只能到来一名顾客;
  • 一位顾客完成交易后,如果后面还有顾客等待,其后的一名顾客接着与柜台交易;
  • 顾客与柜台完成交易后,顾客离去,柜台此时处于空闲状态,等待下一名顾客与之交易。

        平均等待时间就等于所有顾客的等待时间之和除以顾客数量。

        随机事件

        本例中顾客到来就是随机事件。我们可以设定在单位时间内顾客到来的概率,可以理解为平均多长时间来一名顾客。再使用随机数生成器,生成[0, 1]之间的随机数,与顾客到来的概率进行比较,若小于,则顾客到来;若大于,则顾客不会来。


         8.4.2 实现

         系统参数

  • 系统运行时间是25min;
  • 柜台数量是2;
  • 顾客平均交易时间是3min;
  • 平均2min来一名顾客。


         顾客类

         顾客类中有两个属性,一个是ID号码,用于最后的信息打印输出,另一个是顾客到来时间,即第几分钟到来。这个值决定这这名顾客的等待时间。此外,还有两个方法,用于访问这两个属性。

# 顾客类
class Passenger(object):
    def __init__(self, idNum, arrivalTime):
        self._idNum = idNum
        self._arrivalTime = arrivalTime
     
    def idNum(self):
        return self._idNum

    def timeArrived(self):
        return self._arrivalTime

        柜台类

        柜台类中有三个属性,第一个是柜台的编号,第二个是当前顾客交易将会完成的时间,第三个是当前正在进行交易的顾客。另外,还有五个方法,第一个是返回柜台编号,第二个是判断柜台是否处于空闲状态,第三个是判断柜台与顾客是否完成交易,第四个是交易开始,最后一个是交易结束,柜台又处于空闲状态。

# 柜台类
class TicketAgent(object):
    def __init__(self, idNum):
        self._idNum = idNum
        self._passenger = None
        self._stopTime = -1

    # 柜台编号
    def idNum(self):
        return self._idNum

    # 判断柜台是否空闲
    def isFree(self):
        return self._passenger is None

    # 判断柜台与顾客是否完成交易
    def isFinished(self, curTime):
        return self._passenger is not None and self._stopTime == curTime

    # 交易开始,需传入顾客,以及交易结束时间
    def startService(self, passenger, stopTime):
        self._passenger = passenger
        self._stopTime = stopTime

    # 交易结束,柜台又处于空闲状态
    def stopService(self):
        thePassenger = self._passenger
        self._passenger = None
        return thePassenger



      仿真类

      仿真类的属性比较多,首先是三个用户定义的参数,其后是创建队列和柜台实例,最后是两个在运行过程中跟踪的数据,是顾客的等待时间之和以及顾客数量。另外还有五个方法,第一个是运行系统,在一个循环内执行另外三个方法,分别是顾客到来并进入队列、顾客开始交易以及顾客完成交易离去。系统运行结束后,打印结果。

#-*-coding: utf-8-*-

# 仿真类

from myarray import Array
from llistqueue import Queue
from simpeople import TicketAgent, Passenger
from random import random

class TicketCounterSimulation(object):
    def __init__(self, numAgents, numMinutes, betweenTime, serviceTime):
        # 用户定义参数
        self._arriveProb = 1.0 / betweenTime
        self._serviceTime = serviceTime
        self._numMinutes = numMinutes

        # 仿真组件
        self._passengerQ = Queue()
        self._theAgents = Array(numAgents)
        for i in range(numAgents):
            self._theAgents[i] = TicketAgent(i+1)
        
        # 仿真过程中,计算的参数
        self._totalWaitTime = 0
        self._numPassengers = 0

    # 运行仿真
    def run(self):
        for curTime in range(1, self._numMinutes+1):
            self._handleArrival(curTime)
            self._handleBeginService(curTime)
            self._handleEndService(curTime)

    # 打印结果
    def printResults(self):
        numServed = self._numPassengers - len(self._passengerQ) # 所有交易过的顾客人数
        avgWait = float(self._totalWaitTime) / numServed
        print ""
        print "Number of passengers served = %d" % numServed
        print "Number of passengers remaining in line = %d" % len(self._passengerQ)
        print "The average wait time was %4.2f minutes." % avgWait

    # 处理第一条规则
    def _handleArrival(self, curTime):
        odds = random()
        if odds <= self._arriveProb: # 使用随机数生成器,生成[0, 1]之间的随机数,与顾客到来的概率进行比较,若小于,则顾客到来;若大于,则顾客不会来。
            self._numPassengers += 1
            passenger = Passenger(self._numPassengers, curTime) # 使用self._numPassengers来记录顾客的编号
            self._passengerQ.enqueue(passenger) # 顾客进入队列排队 
            print "Time %6d Passenger %d arrived." % (curTime, passenger.idNum())

    # 处理第二条规则
    def _handleBeginService(self, curTime):
        for i in range(len(self._theAgents)):
            if self._theAgents[i].isFree() and not self._passengerQ.isEmpty(): # 查看柜台是否空闲以及队列中是否还有顾客
                passenger = self._passengerQ.dequeue() # 柜台空闲且队列中还有顾客,则将一名顾客出列,到相应的柜台开始交易
                self._totalWaitTime += (curTime - passenger.timeArrived())
                self._theAgents[i].startService(passenger, curTime+self._serviceTime)
                print "Time %6d Agent %d started serving passenger %d" % (curTime, self._theAgents[i].idNum(), passenger.idNum())
                
    # 处理第三条规则
    def _handleEndService(self, curTime):
        for i in range(len(self._theAgents)):
            if self._theAgents[i].isFinished(curTime): # 查看柜台是否已完成交易
                passenger = self._theAgents[i].stopService()
                print "Time %6d Agent %d stopped serving passenger %d" % (curTime, self._theAgents[i].idNum(), passenger.idNum())

if __name__ == "__main__":
    TCSimulation = TicketCounterSimulation(2, 25, 2, 3)
    TCSimulation.run()
    TCSimulation.printResults()




python 飞盘飞行轨迹模拟 基于python的飞行仪表仿真_数据结构