Python のシミュレーション 2
前回は交通渋滞が起こる要素を見てみたが,今回は渋滞を起こさない家庭を見てみたい.
基本的に道路が空いていれば渋滞は起きないはずである.そこで車の台数を減らしてみた.
すると見事に渋滞が起こらなくなった.
import numpy as np
import matplotlib.pyplot as plt
import imageio
import os
# シミュレーションパラメータ
RADIUS = 25 # 円の半径(メートル)
NUM_CARS = 5 # 車の数
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' を確認してください。")