Pythonで駐車場シミュレーション
Pythonを使って駐車場シミュレーションを作ってみました。
駐車場といっても色々ありますが、今回は自走式の立体駐車場でフラット式といわれるタイプで、各階に向かう車路を簡易に再現したもので、駐車マスまでは再現してません。
よくショッピングモールなどで見かけるタイプです。下の階から順に駐車していく様子を再現します。ちなみにフラットタイプは駐車階が名前のとおり、平になっているタイプです。床が傾斜していて螺旋状の車路の両脇に駐車マスがあるのは、連続傾床式というもので、今回、対象としているものではありません。
<シミュレーション実行画面>
シミュレーションの実行画面は以下のような感じです。レトロゲームエンジンを使っていることもあり、ちょっとレトロゲームみたいです。左下に入り口があって、右側の赤っぽい四角が各階の入り口(全7階)になります。四角部のブロックの大きさは8mです。いうまでもありませんが、薄紫の四角のものが車です。
実行環境
PythonとPythonで動作するレトロゲームエンジンのPyxel(ピクセルと読むみたいです。つづりからしてパイセルかと思ってました。^^;)を使用しています。下記を参照してインストールしてみてください。
Pyxelが動くのはPythonのバージョン3.7.0以上なので、私は3.8.0をインストールしました。3.7.0以上なら何でもいいと思います。
Pyxelはゲームエンジンなので、簡単に図を動かすことができるので、今回のようなシミュレーションを表現するのに、とても便利でした。開発者は日本人の方のようですが、感謝です。
シミュレーションモデルの内容
車両の発生
交通量は時間交通量(1時間あたりに発生する交通量)で設定し、時間変動は与えていないです。ポアソン分布による発生分布で発生。
一時間あたり500台発生する設定にしています。
各階の駐車可能台数は80台としています。
車両の動作
制限速度は10/kmとしています。一般的な駐車場内の制限速度は8~10km/hくらいなので、一般的な設定です。車両の挙動は、前方車両との車間距離、相対速度に応じて、加速度を計算する追従モデルの一種でHellyモデルといわれるモデルを使用しています。
具体的な加速度の計算式は下記のとおりです。
自車の加速度 = k1 * (車間距離 - DV) + k2*(先行車の速度 - 自車の速度)
DV = d + Tdes * 自車の速度
k1,d2,D,Tdes パラメータ
パラメータは以下のように設定しました。
k1 = 0.6
k2 = 0.2
Tdes = 0.8
d = 10.0
駐車階の選択行動
駐車場利用者が、どの駐車階を選択するかですが、一般的には下の階を優先して利用していくと考えられます。
これは入り口から近い階のほうが、短時間で駐車できるからです。
また、混雑してくれば止めにくくなるので、混雑状況も関係してくると考えられます。
入り口から各階への距離は以下のようになっています。
フロア 距離(m)
1F 232
2F 488
3F 744
4F 1000
5F 1258
6F 1512
7F 1760
入り口からの距離が長くなるにつれて、利用者にとって効用が減ると考えられることから、各階の駐車場を選択するための効用は、距離に応じて下記のようになると考えました。(満車になると選択率はゼロになる)
距離に応じた効用 = Exp(α*距離)
α:パラメータ(今回はα = -0.003とした。ちなみにαを小さくすると距離が近い方に選択が集中する傾向になります。)
各階の満車率 = 各階の駐車台数 / 各階の駐車マス数
各階の距離・満車率を考慮した効用 = (1.0 - 満車率)*距離に応じた効用
上記から各階への選択率を下記の式で計算しました。
各階の選択率 =
各階の距離・満車率を考慮した効用/距離・満車率を考慮した効用の合計
なお、パラメータの設定は適当であり、根拠はありません。
プログラムの構造
Pyxelでは データの更新、描画は下記のサブルーチンで行うようです。
def update(self): 指定したフレームレート(FPS)で 更新
def draw(self): 描画を行う
これを踏まえ、下記の構成でプログラムを作成しました。
データの初期値の設定 def __init__(self):
各フレームレートでのデータの更新 def update(self):
描画 def draw(self):
フレームレートは、10FSP(つまり0.1秒ごとに1フレーム)に設定し、シミュレーションは1フレーム1秒で演算されます。
演算結果
演算結果はプログラムファイルと同じフォルダに「simdata.txt」というファイル名で保存されます。算出結果の抜粋を下記に示します。
カンマ区切りで、左から車両番号、駐車階数、入り口に入った時間(秒)、駐車階に入った時間(秒)、所要時間(秒)を示します。
vid,ParkingNo,StartTime,EndTime,TravelTime
101,1,11.0,86.0,75.0
102,1,26.0,101.0,75.0
103,1,41.0,116.0,75.0
104,1,44.0,119.0,75.0
105,1,79.0,154.0,75.0
106,1,87.0,157.0,70.0
107,1,93.0,161.0,68.0
108,1,99.0,165.0,66.0
109,1,101.0,169.0,68.0
下図は、この演算結果を元に10分間ごとにどの駐車階に入ったかをグラフ化したものです。(エクセルで集計)
下記に示すように1階から上の階に順に駐車している様子がわかります。
駐車階ごとの平均所要時間を算出すると下記のとおりです。
駐車階 平均所要時間(分)
1階 1.2
2階 2.6
3階 4.1
4階 5.6
5階 7.0
6階 -
7階 -
プログラムコード
プログラムコードを下記に示します。Pythonはあまりなれていないので、おかしな点があるかもしれませんが、ご容赦ください。
下記、プログラムは、ご自由に活用していただいて構いませんが、無断転載はお断りします。
import pyxel
import math
import random
import numpy as np
import copy
class Vehicle:
def __init__(self,vid,length,LinkID,pos,Speed,Route,Endflg,Stime,Etime,ParkingNo):
self.vid = vid # 車両ID
self.length = length # 車長(m)
self.LinkID = LinkID # 走行中のリンクID
self.pos = pos # 走行中のリンク上の位置(m)
self.Speed = Speed # 車両走行速度(km/h)
self.Route = Route # 車両の走行速度
self.Endflg = Endflg # 最後まで走行したかを示すフラグ
self.ParkingNo = ParkingNo # 入庫した駐車階
self.Stime = Stime # スタートした時間(秒)
self.Etime = Etime # ゴールした時間(秒)
class Node:
def __init__(self,nid,x,y,ntype,flg):
self.nid = nid # ノードID
self.x = x # X座標
self.y = y # Y座標
self.ntype = ntype # 1 通路 2:入口 3 分岐部との接続 4 駐車場 5:分岐部
self.flg = flg # フラグ(リンクの自動生成のために使用)
class Link:
def __init__(self,lid,n1,n2,leng):
self.lid = lid # リンクID
self.n1 = n1 # 上流側ノードID
self.n2 = n2 # 下流側ノードID
self.leng = leng # リンクの長さ
class App:
def __init__(self):
def PoissonDistribution(R,AVG,SD): # R:発生回数 AVG:発生間隔 SD:ランダムシード
random.seed(SD)
Val = []
TA = 0
DT = 1
n = 0
while n < R:
rn = random.randint(0,99)*0.01
if rn != 0:
TA = int(-AVG * math.log(rn)+0.999)
Val.append(TA)
n = n + 1
return Val
self.f = open('simdata.txt', 'w')
self.PI = 3.14159265359 # 円周率
self.psize = 8 # リンクの距離
self.Fps = 10 # FPS(フレーム/秒)
pyxel.init(248,216,fps = self.Fps)
self.Time = 0
self.Simtime = 3600 # 車両が発生する時間(秒)
self.SimtimeALL = 4200 # シミュレーション実行時間(秒)
self.TimeStep = 1.0 # シミュレーションタイムステップ(秒)
self.Quantity = 400 # 交通量(台/時)
self.ParkingCapcity = 80 # 1フロアごとの駐車台数(台)
self.k1 = 0.6 # 追従モデルパラメータ k1
self.k2 = 0.2 # 追従モデルパラメータ k2
self.Tdes = 0.8 # 追従モデルパラメータ Tdes
self.d = 10.0 # 追従モデルパラメータ d
self.alpha = -0.003 # 効用関数パラメータ
self.Speed = 10.0 # 制限速度(km/h)
self.wsize = 31 # マップサイズ横
self.hsize = 27 # マップサイズ縦
self.MaxHeight = self.hsize*self.psize
self.nodelist = [] # ノードリスト
self.linklist = [] # リンクリスト
self.PDis = [] # 車両発生フラグ
self.VID = 100 # 車両IDの初期値
self.VehicleQueue = [] # 待ち行列の配列
self.MovingVehicle = [] # 走行している車両の配列
self.CountCar = [] # 駐車台数
self.ParkingPos = [] # 駐車場位置
self.ParkingLinkID = [] # 各駐車階入口リンク
self.BLinkID = [] # 分岐部のリンク
self.PRate = [] # 満車率
self.TC = [] # 距離による効用
self.ATC = [] # 効用関数
self.TRate = [] # 選択率
self.BRate = [] # 分岐率
PD = []
PDS = []
PT = 0
SD = 3278 # ランダムシード
T = self.Simtime / 3600
R = self.Quantity * T # シミュレーション時間内に発生する車両台数
AVG = self.Simtime / R # 平均車両発生間隔
PD = PoissonDistribution(R,AVG,SD) # 車両発生間隔の分布(何秒間隔で車両が発生するか)
for i in range(len(PD)):
if PD[i] != 0:
PT = PT + PD[i]
PDS.append(PT)
for i in range(int(self.Simtime)): # PDの発生分布を1秒ごとの車両の発生フラグを作成
self.PDis.append(0)
for j in range(len(PDS)):
if PDS[j] == i:
self.PDis[i] = 1 #
nid = 0
nx = 0
ny = 0
lid = 0
hl = int(pyxel.height/self.psize)
wl = int(pyxel.width/self.psize)
# 横31 x 縦23 のマップ(図化のイメージとは上下逆になるので注意) 1 通路 2:入口 3 分岐部との接続 4 駐車場 5:分岐部
self.maplist = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,3,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,3,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,3,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,3,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,3,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,3,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
]
for i in range(self.wsize):
for j in range(self.hsize):
if self.maplist[j][i] == 1:
nid = nid + 1
nx = self.psize*i + self.psize*0.5
ny = self.psize*j + self.psize*0.5
node = Node(nid,nx,ny,1,0)
self.nodelist.append(node)
if self.maplist[j][i] == 2:
nid = nid + 1
nx = self.psize*i + self.psize*0.5
ny = self.psize*j + self.psize*0.5
node = Node(nid,nx,ny,2,0)
self.nodelist.append(node)
if self.maplist[j][i] == 3:
nid = nid + 1
nx = self.psize*i + self.psize*0.5
ny = self.psize*j + self.psize*0.5
node = Node(nid,nx,ny,3,0)
self.nodelist.append(node)
if self.maplist[j][i] == 4:
nid = nid + 1
nx = self.psize*i + self.psize*0.5
ny = self.psize*j + self.psize*0.5
node = Node(nid,nx,ny,4,0)
self.nodelist.append(node)
if self.maplist[j][i] == 5:
nid = nid + 1
nx = self.psize*i + self.psize*0.5
ny = self.psize*j + self.psize*0.5
node = Node(nid,nx,ny,5,0)
self.nodelist.append(node)
# 起点からスタートするリンクの生成
self.Route = []
le = 0
for i in range(len(self.nodelist)):
if self.nodelist[i].ntype == 2: # 入り口ノードの場合
snode = self.nodelist[i] # 入り口ノード
node = Node(self.nodelist[i].nid,self.nodelist[i].x,self.nodelist[i].y,self.nodelist[i].ntype,1)
self.nodelist[i].flg = 1
sn = snode
a = 0
while a == 0:
a = 1
for j in range(len(self.nodelist)):
le = math.sqrt((sn.x - self.nodelist[j].x)**2 + (sn.y - self.nodelist[j].y)**2)
if (le == self.psize) and (self.nodelist[j].flg == 0) and (self.nodelist[j].ntype != 3):# 距離がself.psizeで分岐を経由しないルート
lid = lid + 1
link = Link(lid,sn.nid,self.nodelist[j].nid,le)
self.linklist.append(link)
node = Node(self.nodelist[j].nid,self.nodelist[j].x,self.nodelist[j].y,self.nodelist[j].ntype,1)
self.nodelist[j].flg = 1
sn = node
a = 0
self.Route.append(copy.copy(link)) # 本線のルート(リンクの配列)
# 分岐点からスタートするリンクの生成
le = 0
self.bnode = [] # 分岐ルートのノード配列
for i in range(len(self.nodelist)):
if self.nodelist[i].ntype == 5: # 分岐点のノードだったら
self.bnode.append(self.nodelist[i])
self.BRoute = [] # 分岐ルートのリンク配列
for i in range(len(self.bnode)):
bn = self.bnode[i]
br = []
a = 0
while a == 0:
a = 1
for j in range(len(self.nodelist)):
le = math.sqrt((bn.x - self.nodelist[j].x)**2 + (bn.y - self.nodelist[j].y)**2)
if (le == self.psize) and (self.nodelist[j].flg == 0):
lid = lid + 1
link = Link(lid,bn.nid,self.nodelist[j].nid,le)
self.linklist.append(link)
node = Node(self.nodelist[j].nid,self.nodelist[j].x,self.nodelist[j].y,self.nodelist[j].ntype,1)
self.nodelist[j].flg = 1
bn = node
a = 0
br.append(copy.copy(link))
self.BRoute.append(br) # 分岐先のルート
bs = 0
for i in range(len(self.Route)):
bs = bs + self.Route[i].leng
bl = 0
self.blength = [] # 各階への距離
for i in range(len(self.Route)):
nf = 0
for j in range(len(self.nodelist)):
if self.Route[i].n2 == self.nodelist[j].nid:
nf = self.nodelist[j].ntype
bl = bl + self.Route[i].leng
if nf == 5:
self.blength.append(bl)
for i in range(len(self.BRoute)):
bl = 0
for j in range(len(self.BRoute[i])):
b = self.BRoute[i]
bl = bl + b[j].leng
self.blength[i] = self.blength[i] + bl
self.blength.append(bs)
for i in range(len(self.nodelist)):
if self.nodelist[i].ntype == 5:
Blid = 0
for j in range(len(self.linklist)):
if self.nodelist[i].nid == self.linklist[j].n2:
Blid = self.linklist[j].lid
self.BLinkID.append(Blid)
if self.nodelist[i].ntype == 4:
self.CountCar.append(0)
self.PRate.append(0)
self.TC.append(0)
self.ATC.append(0)
self.TRate.append(0)
self.BRate.append(0)
self.ParkingPos.append(copy.copy(self.nodelist[i])) # 駐車場位置
Plid = 0
for j in range(len(self.linklist)):
if self.nodelist[i].nid == self.linklist[j].n2:
Plid = self.linklist[j].lid
self.ParkingLinkID.append(Plid)
self.f.write('vid,ParkingNo,StartTime,EndTime,TravelTime\n') # シミュレーション結果出力のヘッダ
pyxel.run(self.update,self.draw)
def update(self):
AT = 0.0
for i in range(len(self.CountCar)):
self.PRate[i] = self.CountCar[i]/self.ParkingCapcity # 満車率
if self.PRate[i] > 1.0:
self.PRate[i] = 1.0
self.TC[i] = math.exp(self.alpha * self.blength[i]) # 距離に応じた効用(距離が短いほど高い)
self.ATC[i] = (1.0 - self.PRate[i]) * self.TC[i] # 満車率・距離を踏まえた効用(距離が近い・満車率が低いほど高い)
AT = AT + self.ATC[i] # 効用の合計
for i in range(len(self.CountCar)):
if AT != 0:
self.TRate[i] = self.ATC[i] / AT # 各駐車階の選択率
else:
self.TRate[i] = 0.0
for i in range(len(self.CountCar)):
if i == 0:
self.BRate[i] = self.TRate[i]
else:
if self.TRate[i-1] != 0:
self.BRate[i] = self.TRate[i]/self.TRate[i-1] # 分岐率
else:
self.BRate[i] = self.TRate[i]
sx = 0
sy = 0
self.Time = pyxel.frame_count * self.TimeStep
slid = self.linklist[0].lid # 起点部のリンク番号
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
if self.Time > self.SimtimeALL:
pyxel.quit()
for i in range(len(self.PDis)): # 交通量の発生
if (int(self.Time) == i) and (self.PDis[i] == 1):
sx = self.nodelist[0].x
sy = self.nodelist[0].y
self.VID = self.VID + 1
vehicle = Vehicle(self.VID,4.5,0,0,self.Speed,self.Route,0,-99,-99,-99)
self.VehicleQueue.append(vehicle) # 車両が発生したら待ち行列の配列にいれる
gflg = 0
for i in range(len(self.MovingVehicle)): # 起点にリンク上に車両がいるかをチェック
if slid == self.MovingVehicle[i].LinkID:
gflg = 1
if (gflg == 0) and (len(self.VehicleQueue) > 0): # 起点リンク上に車両がいない
R = copy.copy(self.Route)
Vin = Vehicle(self.VehicleQueue[0].vid,self.VehicleQueue[0].length,slid,0,self.VehicleQueue[0].Speed,R,0,self.Time,-99,-99)
if len(Vin.Route) != 0:
Vin.Route.pop(0)
self.MovingVehicle.append(Vin)
if len(self.VehicleQueue) != 0:
self.VehicleQueue.pop(0) # 起点リンクに車両が流入したら待ち行列から削除する
for i in range(len(self.MovingVehicle)):
for k in range(len(self.BLinkID)): # 分岐処理
B = self.BRate[k]*100 # 分岐率(%)
rn = random.randint(0,99) # 0~100の乱数
if B > rn: # 分岐率 > 乱数
if len(self.MovingVehicle[i].Route) >= 2: # 駐車場への分岐
if self.MovingVehicle[i].Route[1].lid == self.BLinkID[k]:
rnum = len(self.MovingVehicle[i].Route)
self.MovingVehicle[i].Route[2:rnum] = [] # 上層階のルートを削除
for m in range(len(self.BRoute[k])): # 駐車場に向かうルートを追加
self.MovingVehicle[i].Route.append(self.BRoute[k][m])
dp = -99
fv = self.Speed
for j in range(len(self.MovingVehicle)):
if self.MovingVehicle[i].vid != self.MovingVehicle[j].vid:# 先行車のサーチ
vlen = self.MovingVehicle[j].length*0.5 -self.MovingVehicle[i].length*0.5
dflg = 0
if self.MovingVehicle[i].LinkID == self.MovingVehicle[j].LinkID:# 同じリンクに他車がいる
if self.MovingVehicle[i].pos < self.MovingVehicle[j].pos: # 他車が前にいる
dp = self.MovingVehicle[j].pos - self.MovingVehicle[i].pos - vlen # 車間距離
dflg = 1
fv = self.MovingVehicle[j].Speed # 先行車の速度
if (dflg == 0) and (len(self.MovingVehicle[i].Route) >= 2):
if self.MovingVehicle[i].Route[1].lid == self.MovingVehicle[j].LinkID:# 一つ先のリンクに他車がいる
l1 = self.MovingVehicle[i].Route[1].leng
dp = self.MovingVehicle[j].pos - self.MovingVehicle[i].pos + l1 - vlen # 車間距離
dflg = 1
fv = self.MovingVehicle[j].Speed # 先行車の速度
if (dflg == 0) and len(self.MovingVehicle[i].Route) >= 3:
if self.MovingVehicle[i].Route[2].lid == self.MovingVehicle[j].LinkID:# 2つ先のリンクに他車がいる
l1 = self.MovingVehicle[i].Route[1].leng + self.MovingVehicle[i].Route[0].leng
dp = self.MovingVehicle[j].pos - self.MovingVehicle[i].pos + l1 - vlen # 車間距離
dflg = 1
fv = self.MovingVehicle[j].Speed # 先行車の速度
if (dflg == 0) and len(self.MovingVehicle[i].Route) >= 4:
if self.MovingVehicle[i].Route[3].lid == self.MovingVehicle[j].LinkID:# 3つ先のリンクに他車がいる
l1 = self.MovingVehicle[i].Route[2].leng + self.MovingVehicle[i].Route[1].leng + self.MovingVehicle[i].Route[0].leng
dp = self.MovingVehicle[j].pos - self.MovingVehicle[i].pos + l1 - vlen # 車間距離
dflg = 1
fv = self.MovingVehicle[j].Speed # 先行車の速度
if (dflg == 0) and len(self.MovingVehicle[i].Route) >= 5:
if self.MovingVehicle[i].Route[4].lid == self.MovingVehicle[j].LinkID:# 4つ先のリンクに他車がいる
l1 = self.MovingVehicle[i].Route[3].leng + self.MovingVehicle[i].Route[2].leng + self.MovingVehicle[i].Route[1].leng + self.MovingVehicle[i].Route[0].leng
dp = self.MovingVehicle[j].pos - self.MovingVehicle[i].pos + l1 - vlen # 車間距離
dflg = 1
fv = self.MovingVehicle[j].Speed # 先行車の速度
acc = 0
if dp > 0:
yd = (fv - self.MovingVehicle[i].Speed)/3.6
dv = self.d + self.Tdes * self.MovingVehicle[i].Speed/3.6
acc = self.k1 * (dp - dv) + self.k2 * (fv - self.MovingVehicle[i].Speed)/3.6
else:
acc = 1.0 # 先頭車両の場合
if self.MovingVehicle[i].Speed <= self.Speed:
self.MovingVehicle[i].Speed = self.MovingVehicle[i].Speed + acc * self.TimeStep
if self.MovingVehicle[i].Speed < 0:
self.MovingVehicle[i].Speed = 0.0
else:
self.MovingVehicle[i].Speed = self.Speed
lp = self.MovingVehicle[i].pos + (self.MovingVehicle[i].Speed / 3.6)
lid = self.MovingVehicle[i].LinkID
if len(self.MovingVehicle[i].Route) >= 1:
nextlink1 = self.MovingVehicle[i].Route[0]
if len(self.MovingVehicle[i].Route) >= 2:
nextlink2 = self.MovingVehicle[i].Route[1]
leng1 = 0.0
leng2 = 0.0
if len(self.MovingVehicle[i].Route) >= 2:
leng1 = nextlink1.leng
leng2 = nextlink2.leng
if lp < leng1:
self.MovingVehicle[i].pos = lp
elif lp < (leng1 + leng2):
self.MovingVehicle[i].pos = lp - leng1
self.MovingVehicle[i].LinkID = nextlink2.lid
self.MovingVehicle[i].Route.pop(0)
else:
self.MovingVehicle[i].Endflg = 1
for i in range(len(self.MovingVehicle)):
for j in range(len(self.ParkingLinkID)):
if (self.MovingVehicle[i].LinkID == self.ParkingLinkID[j]) and (self.MovingVehicle[i].Endflg == 1):
self.CountCar[j] = self.CountCar[j] + 1
self.MovingVehicle[i].Etime = self.Time
TraTim = self.MovingVehicle[i].Etime - self.MovingVehicle[i].Stime
self.MovingVehicle[i].ParkingNo = j+1
# シミュレーション結果出力
self.f.write(str(self.MovingVehicle[i].vid) + ',' + str(self.MovingVehicle[i].ParkingNo) +',' + str(self.MovingVehicle[i].Stime) + ',' + str(self.MovingVehicle[i].Etime) + ',' + str(TraTim)+'\n')
for i in reversed(range(len(self.MovingVehicle))):
if self.MovingVehicle[i].Endflg == 1:
del self.MovingVehicle[i]
def draw(self): # 画面の描画
class VPoint: # 車両の座標、角度の情報を格納する変数
def __init__(self,x,y,ang):
self.x = x # X座標
self.y = y # Y座標
self.ang = ang # 角度
def VehiclePos(LinkID,pos): # LinkID、posを入力値として、車の座標、角度を求める
px = 0.0
py = 0.0
n1x = 0.0
n1y = 0.0
n2x = 0.0
n2y = 0.0
ang = 0.0
for i in range(len(self.linklist)):
if LinkID == self.linklist[i].lid:
np1 = self.linklist[i].n1
np2 = self.linklist[i].n2
for j in range(len(self.nodelist)):
if np1 == self.nodelist[j].nid:
n1x = self.nodelist[j].x
n1y = self.nodelist[j].y
if np2 == self.nodelist[j].nid:
n2x = self.nodelist[j].x
n2y = self.nodelist[j].y
r = math.sqrt((n2x - n1x)** 2 + (n2y - n1y)**2)
ang = math.atan2((n2y - n1y),(n2x - n1x))
px = n1x + pos * math.cos(ang)
py = n2y + pos * math.sin(ang)
Vp = VPoint(px,py,ang)
return Vp
pyxel.cls(0) # 画面クリア
pyxel.rect(0,0,pyxel.width,pyxel.height,13) # 背景描画
hl = int(pyxel.height/self.psize)
wl = int(pyxel.width/self.psize)
for i in range(hl): # 横線の描画
pyxel.line(0,self.psize*i,pyxel.width,self.psize*i,4)
for i in range(wl): # 縦線の描画
pyxel.line(self.psize*i,0,self.psize*i,pyxel.height,4)
for i in range(self.wsize): # ノード属性を示すピクセルを描画
for j in range(self.hsize):
if self.maplist[j][i] == 1: # 通路
pyxel.rect(self.psize*i,self.psize*(self.hsize - j -1),self.psize,self.psize,1)
if self.maplist[j][i] == 2: # 入口
pyxel.rect(self.psize*i,self.psize*(self.hsize - j -1),self.psize,self.psize,2)
if self.maplist[j][i] == 3: # 分岐部との接続
pyxel.rect(self.psize*i,self.psize*(self.hsize - j -1),self.psize,self.psize,3)
if self.maplist[j][i] == 4: # 駐車場
pyxel.rect(self.psize*i,self.psize*(self.hsize - j -1),self.psize,self.psize,4)
if self.maplist[j][i] == 5: # 分岐部
pyxel.rect(self.psize*i,self.psize*(self.hsize - j -1),self.psize,self.psize,5)
for i in range(len(self.linklist)): # リンクの描画
p1x = 0
p1y = 0
p2x = 0
p2y = 0
for j in range(len(self.nodelist)):
if self.linklist[i].n1 == self.nodelist[j].nid:
p1x = self.nodelist[j].x
p1y = self.nodelist[j].y
if self.linklist[i].n2 == self.nodelist[j].nid:
p2x = self.nodelist[j].x
p2y = self.nodelist[j].y
pyxel.line(p1x,self.MaxHeight - p1y,p2x,self.MaxHeight - p2y,7)
for i in range(len(self.MovingVehicle)): # 車の描画
lid = self.MovingVehicle[i].LinkID
P = self.MovingVehicle[i].pos
VL = self.MovingVehicle[i].length
V = VehiclePos(lid,P)
X = V.x
Y = V.y
FX = X + 3 * math.cos(V.ang)
FY = Y + 3 * math.sin(V.ang)
BX = X - 3 * math.cos(V.ang)
BY = Y - 3 * math.sin(V.ang)
F1x = FX + VL*0.5 * math.cos(V.ang + self.PI*0.5)
F1y = FY + 2 * math.sin(V.ang + self.PI*0.5)
F2x = FX + VL*0.5 * math.cos(V.ang - self.PI*0.5)
F2y = FY + 2 * math.sin(V.ang - self.PI*0.5)
B1x = BX + VL*0.5 * math.cos(V.ang + self.PI*0.5)
B1y = BY + 2 * math.sin(V.ang + self.PI*0.5)
B2x = BX + VL*0.5 * math.cos(V.ang - self.PI*0.5)
B2y = BY + 2 * math.sin(V.ang - self.PI*0.5)
pyxel.tri(F1x,self.MaxHeight - F1y,F2x,self.MaxHeight - F2y,B2x,self.MaxHeight - B2y,6) # 三角形を二つで車両を表現
pyxel.tri(B2x,self.MaxHeight - B2y,B1x,self.MaxHeight - B1y,F1x,self.MaxHeight - F1y,6)
s = str(self.Time)
pyxel.text(1,1,s,1)
for i in range(len(self.CountCar)):
s= str(self.CountCar[i])
pyxel.text(self.ParkingPos[i].x,self.MaxHeight - self.ParkingPos[i].y,s,1) # 駐車台数を表示
App()