Python のシミュレーション
最近,計算社会学というものにふれ,色々と試している.
今回は,交通渋滞のシミュレーションをしてみたい.
今回はこんな条件でシミュレーションを実施する.すると,見事に渋滞が起こって面白い.
1. テストコースの定義:
• 半径25mの円形コース(周長約157.08m)を設定。
• 20台の車両を等間隔(約7.85m)で配置。
2. 車両エージェントの特性:
• 初期速度: 20 km/h(約5.56 m/s)。
• 各車両は前方車両との距離に基づいて速度を調整。
• 近づきすぎた場合: 速度を15 km/h(約4.17 m/s)に減速。
• 十分な車間距離がある場合: 速度を20 km/hに加速。
• 各シミュレーションステップごとに速度に±0.05 km/h(約0.0139 m/s)のゆらぎを追加。
import numpy as np
import matplotlib.pyplot as plt
import imageio
import os
# シミュレーションパラメータ
RADIUS = 25 # 円の半径(メートル)
NUM_CARS = 20 # 車の数
CIRCUMFERENCE = 2 * np.pi * RADIUS # 円の周長
INITIAL_SPACING = CIRCUMFERENCE / NUM_CARS # 初期車間距離
TARGET_SPEED = 20 / 3.6 # 目標速度(m/s)20 km/h
BRAKE_SPEED = 15 / 3.6 # 減速後の速度(m/s)15 km/h
MIN_DISTANCE = 5 # 最小車間距離(メートル)
SAFE_DISTANCE = 10 # 安全車間距離(メートル)
DELTA_T = 1 # 時間ステップ(秒)
TOTAL_STEPS = 200 # シミュレーションの総ステップ数
SPEED_FLUCTUATION = 0.05 / 3.6 # 速度のゆらぎ(m/s)
# 初期位置と速度の設定
positions = np.linspace(0, CIRCUMFERENCE, NUM_CARS, endpoint=False)
speeds = np.full(NUM_CARS, TARGET_SPEED)
# アニメーション用のフレームを保存するリスト
frames = []
# 一時的なフォルダを作成してフレームを保存
frame_dir = "frames"
if not os.path.exists(frame_dir):
os.makedirs(frame_dir)
for step in range(TOTAL_STEPS):
# ソートされた位置のインデックス
sorted_indices = np.argsort(positions)
sorted_positions = positions[sorted_indices]
sorted_speeds = speeds[sorted_indices]
# 距離を計算(前の車との距離)
distances = np.roll(sorted_positions, -1) - sorted_positions
distances[-1] += CIRCUMFERENCE # 最後の車は最初の車との距離
# 速度の更新
new_speeds = sorted_speeds.copy()
for i in range(NUM_CARS):
distance = distances[i]
if distance < MIN_DISTANCE:
# 近づきすぎた場合、減速
new_speeds[i] = BRAKE_SPEED
elif distance > SAFE_DISTANCE:
# 十分な距離がある場合、加速
new_speeds[i] = TARGET_SPEED
# それ以外は現在の速度を維持
# 速度にゆらぎを追加
fluctuations = np.random.uniform(-SPEED_FLUCTUATION, SPEED_FLUCTUATION, NUM_CARS)
new_speeds += fluctuations
# 速度の範囲を制限(例: 0から30 km/h)
new_speeds = np.clip(new_speeds, 0, 30 / 3.6)
speeds[sorted_indices] = new_speeds
# 位置の更新
positions += speeds * DELTA_T
positions = positions % CIRCUMFERENCE # 周長を超えたらリセット
# プロット用のフレーム作成
plt.figure(figsize=(6,6))
ax = plt.gca()
ax.set_xlim(-RADIUS-5, RADIUS+5)
ax.set_ylim(-RADIUS-5, RADIUS+5)
ax.set_aspect('equal')
plt.axis('off')
# 円形コースの描画
circle = plt.Circle((0, 0), RADIUS, color='black', fill=False, linewidth=2)
ax.add_artist(circle)
# 車両の位置をプロット
angles = (positions / CIRCUMFERENCE) * 2 * np.pi
x = RADIUS * np.cos(angles)
y = RADIUS * np.sin(angles)
plt.scatter(x, y, color='red', s=50)
# フレームの保存
frame_path = os.path.join(frame_dir, f"frame_{step:04d}.png")
plt.savefig(frame_path)
plt.close()
frames.append(frame_path)
# プログレス表示
if (step + 1) % 20 == 0:
print(f"ステップ {step + 1}/{TOTAL_STEPS} 完了")
# GIFアニメーションの作成
images = []
for frame_path in frames:
images.append(imageio.imread(frame_path))
imageio.mimsave('traffic_simulation.gif', images, fps=5)
# フレーム画像の削除(オプション)
for frame_path in frames:
os.remove(frame_path)
os.rmdir(frame_dir)
print("シミュレーションとGIFの作成が完了しました。'traffic_simulation.gif' を確認してください。")
参考文献