--- id: wiki-2026-0508-pedestrian-modeling title: Pedestrian Modeling category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Crowd Simulation, Pedestrian Dynamics, Foot Traffic Modeling] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [simulation, agent-based, urban-planning, crowd-dynamics] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: Python framework: Mesa / SUMO / PyTorch --- # Pedestrian Modeling ## 매 한 줄 > **"매 보행자는 force field 위의 agent"**. 1995년 Helbing의 Social Force Model이 분야를 정의했고, 2026 현재 ML-augmented agent-based simulation (Mesa 3.x, MATSim, SUMO)이 evacuation planning, station design, retail flow 분석의 표준 도구다. ## 매 핵심 ### 매 모델 계열 - **Macroscopic**: fluid-like density/flow PDE — Hughes model, LWR for crowds. 매 large-scale aggregate. - **Mesoscopic**: cellular automata (Burstedde 2001) — discrete grid + transition probabilities. - **Microscopic**: 개별 agent — Social Force (Helbing-Molnár), ORCA (reciprocal velocity obstacles), RVO2. - **Data-driven**: GNN trajectory prediction (Social-LSTM, Trajectron++, EqMotion 2025). ### 매 Social Force 핵심 - 매 보행자 i 의 motion equation: `m_i * dv_i/dt = F_desired + ΣF_social + ΣF_obstacle + ξ`. - `F_desired = (v_target - v_i) / τ` — 매 goal-directed term. - `F_social = A * exp((r_ij - d_ij)/B) * n_ij` — 매 repulsion exponential. ### 매 응용 1. Evacuation simulation (역, stadium, 고층빌딩). 2. Urban design (sidewalk width, crossing geometry, wayfinding). 3. Retail analytics (store layout heatmap). 4. Autonomous robot navigation in crowds. ## 💻 패턴 ### Social Force Model (Mesa 3.x) ```python import numpy as np from mesa import Agent, Model from mesa.space import ContinuousSpace class Pedestrian(Agent): def __init__(self, model, pos, target, v_desired=1.34): super().__init__(model) self.pos = np.array(pos, dtype=float) self.vel = np.zeros(2) self.target = np.array(target, dtype=float) self.v_desired = v_desired self.tau = 0.5 # relaxation time self.radius = 0.3 def desired_force(self): direction = self.target - self.pos norm = np.linalg.norm(direction) + 1e-9 e = direction / norm return (self.v_desired * e - self.vel) / self.tau def social_force(self, A=2000, B=0.08): f = np.zeros(2) for other in self.model.agents: if other is self: continue r_ij = self.radius + other.radius d_vec = self.pos - other.pos d_ij = np.linalg.norm(d_vec) + 1e-9 n_ij = d_vec / d_ij f += A * np.exp((r_ij - d_ij) / B) * n_ij return f def step(self): f = self.desired_force() + self.social_force() self.vel += f * self.model.dt speed = np.linalg.norm(self.vel) if speed > 1.5 * self.v_desired: self.vel *= 1.5 * self.v_desired / speed self.pos += self.vel * self.model.dt ``` ### ORCA (RVO2) collision avoidance ```python import rvo2 sim = rvo2.PyRVOSimulator( timeStep=1/30, neighborDist=2.0, maxNeighbors=10, timeHorizon=2.0, timeHorizonObst=2.0, radius=0.3, maxSpeed=1.5 ) agents = [sim.addAgent((x, y)) for x, y in spawn_positions] for i, goal in enumerate(goals): pref = np.array(goal) - np.array(sim.getAgentPosition(i)) pref = pref / (np.linalg.norm(pref) + 1e-9) * 1.34 sim.setAgentPrefVelocity(i, tuple(pref)) sim.doStep() ``` ### Trajectory prediction (PyTorch GNN, 2025-style) ```python import torch, torch.nn as nn from torch_geometric.nn import GATv2Conv class TrajectronLite(nn.Module): def __init__(self, hidden=64, future=12): super().__init__() self.encoder = nn.GRU(4, hidden, batch_first=True) self.gat = GATv2Conv(hidden, hidden, heads=4, concat=False) self.decoder = nn.GRU(hidden, hidden, batch_first=True) self.head = nn.Linear(hidden, 2) self.future = future def forward(self, hist, edge_index): # hist: (N, T, 4) — (x, y, vx, vy) h, _ = self.encoder(hist) h = self.gat(h[:, -1], edge_index) h = h.unsqueeze(1).expand(-1, self.future, -1) out, _ = self.decoder(h) return self.head(out) # (N, future, 2) ``` ### SUMO foot traffic export ```python import traci traci.start(["sumo", "-c", "station.sumocfg"]) while traci.simulation.getMinExpectedNumber() > 0: traci.simulationStep() for pid in traci.person.getIDList(): x, y = traci.person.getPosition(pid) v = traci.person.getSpeed(pid) log(pid, x, y, v) traci.close() ``` ### Density heatmap (post-hoc) ```python import numpy as np, matplotlib.pyplot as plt from scipy.stats import gaussian_kde xy = trajectories[:, :, :2].reshape(-1, 2).T # (2, N*T) kde = gaussian_kde(xy, bw_method=0.15) gx, gy = np.mgrid[0:50:200j, 0:50:200j] density = kde(np.vstack([gx.ravel(), gy.ravel()])).reshape(gx.shape) plt.imshow(density.T, origin="lower", extent=(0, 50, 0, 50), cmap="hot") ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Evacuation + dense crowd | Social Force (Helbing) | | Smooth navigation, robotics | ORCA / RVO2 | | Trajectory prediction (ML) | Trajectron++ / EqMotion | | Large-scale urban (10⁵+) | Macroscopic LWR / MATSim | | Discrete cell-based grid | Cellular Automata (Burstedde) | **기본값**: Mesa 3.x + Social Force for simulation, RVO2 for robot integration. ## 🔗 Graph - 부모: [[Complex Systems]] - 변형: [[Cellular Automata]] ## 🤖 LLM 활용 **언제**: parameter sweep design, scenario script generation, calibration code 작성. **언제 X**: real-time inner-loop force computation — 매 numerical kernel은 Cython/Numba/CUDA. ## ❌ 안티패턴 - **Pseudo-uniform spawning**: 매 corner clustering 발생 — Poisson disk sampling 사용. - **Naive O(N²) social force**: 매 KD-tree neighborhood 로 cutoff (보통 5m). - **Validation skip**: 매 fundamental diagram (density vs flow) 와 비교 필수. - **dt too large**: 매 0.05–0.1s 권장; 매 그 이상 instability. ## 🧪 검증 / 중복 - Verified (Helbing & Molnár 1995, Helbing et al. 2000 Nature, Mesa docs 3.x, RVO2 reference). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Social Force / ORCA / GNN trajectory FULL content |