irsim.lib.algorithm.social_force_model ====================================== .. py:module:: irsim.lib.algorithm.social_force_model .. autoapi-nested-parse:: Social Force Model (SFM) for pedestrian / mobile-agent navigation. Independent Python implementation of the Social Force Model described in: Helbing, D. & Molnar, P. (1995), *Social force model for pedestrian dynamics.* Phys. Rev. E 51:4282. Moussaid, M., Helbing, D., Garnier, S., Johansson, A., Combe, M., Theraulaz, G. (2009), *Experimental study of the behavioural mechanisms underlying self-organization in human crowds.* Proc. R. Soc. B 276:2755. The neighbor interaction is the anisotropic, velocity-aware variant from Moussaid-Helbing (2009); the obstacle term is the Helbing-Molnar (1995) summation form -- every nearby line obstacle contributes an exponentially decayed push, which (unlike a nearest-segment-only rule) lets symmetric walls cancel and keeps the agent on the centreline. Each agent integrates Newton-like dynamics ``v += dt * a`` where ``a`` is the weighted sum of three forces: * desired force -- relaxation of velocity toward ``v0 * e_goal``; * social force -- anisotropic repulsion from each neighbor (Moussaid-Helbing 2009 form); * obstacle force -- exponential repulsion summed over all line obstacles within ``5 * sigma_obstacle`` (Helbing-Molnar 1995 form). Acknowledgement: pedsim_ros (https://github.com/srl-freiburg/pedsim_ros) and its vendored ``libpedsim`` by Christian Gloor were consulted as reference implementations while writing this module. Attributes ---------- .. autoapisummary:: irsim.lib.algorithm.social_force_model.state_a Classes ------- .. autoapisummary:: irsim.lib.algorithm.social_force_model.social_force_model Module Contents --------------- .. py:class:: social_force_model(state: list, neighbor_list: list | None = None, line_obs_list: list | None = None, vmax: float = 1.5, step_time: float = 0.1, relaxation_time: float = 0.5, force_factor_desired: float = 1.0, force_factor_social: float = 2.1, force_factor_obstacle: float = 10.0, sigma_obstacle: float = 0.8, lambda_importance: float = 2.0, gamma: float = 0.35, n_angular: float = 2.0, n_velocity: float = 3.0, neighbor_range: float = 10.0, safety_radius: float = 0.0) Social Force Model controller for a single agent. The interface mirrors :class:`reciprocal_vel_obs` so the two algorithms are interchangeable from a behavior method. :param state: Agent state ``[x, y, vx, vy, radius, vx_des, vy_des, theta]``. :type state: list :param neighbor_list: Other moving/static circular agents ``[[x, y, vx, vy, radius], ...]``. :type neighbor_list: list :param line_obs_list: Line obstacles ``[[x1, y1, x2, y2], ...]``. :type line_obs_list: list :param vmax: Speed cap applied after the velocity update. :type vmax: float :param step_time: Integration step ``dt``. :type step_time: float :param relaxation_time: ``tau`` in the desired-force term. :type relaxation_time: float :param force_factor_desired: Weight ``alpha_D`` on the desired force. :type force_factor_desired: float :param force_factor_social: Weight ``alpha_S`` on the social force. :type force_factor_social: float :param force_factor_obstacle: Weight ``alpha_O`` on the obstacle force. :type force_factor_obstacle: float :param sigma_obstacle: Decay length of the obstacle repulsion. :type sigma_obstacle: float :param lambda_importance: Weight of relative velocity in the interaction direction (``lambda`` in Moussaïd 2009). :type lambda_importance: float :param gamma: Sets the interaction range ``B = gamma * ||t||``. :type gamma: float :param n_angular: Angular sharpness ``n`` for the sideways force. :type n_angular: float :param n_velocity: Angular sharpness ``n'`` for the slowdown force. :type n_velocity: float :param neighbor_range: Max distance for an agent to count as a social-force neighbor. :type neighbor_range: float :param safety_radius: Personal-space buffer subtracted from the agent-to-agent distance inside the social-force exponential. ``0`` reproduces the upstream behavior (point agents). ``> 0`` shifts the decay closer-in so the repulsion saturates at ``2 * safety_radius`` of centre-to-centre clearance, effectively giving each agent a body radius for SFM. :type safety_radius: float .. py:attribute:: state .. py:attribute:: neighbor_list .. py:attribute:: line_obs_list .. py:attribute:: vmax :value: 1.5 .. py:attribute:: step_time :value: 0.1 .. py:attribute:: relaxation_time :value: 0.5 .. py:attribute:: force_factor_desired :value: 1.0 .. py:attribute:: force_factor_social :value: 2.1 .. py:attribute:: force_factor_obstacle :value: 10.0 .. py:attribute:: sigma_obstacle :value: 0.8 .. py:attribute:: lambda_importance :value: 2.0 .. py:attribute:: gamma :value: 0.35 .. py:attribute:: n_angular :value: 2.0 .. py:attribute:: n_velocity :value: 3.0 .. py:attribute:: neighbor_range :value: 10.0 .. py:attribute:: safety_radius :value: 0.0 .. py:method:: update(state: list, neighbor_list: list, line_obs_list: list | None = None) -> None Refresh the per-step inputs without re-instantiating. .. py:method:: cal_vel() -> list Integrate one SFM step and return the new global velocity. :returns: Updated velocity ``[vx, vy]``, clipped to ``vmax``. :rtype: list[float] .. py:method:: desired_force() -> list Relaxation toward the desired velocity ``v0 * e_goal``. The desired velocity is supplied directly via ``state[5:7]``. .. py:method:: social_force() -> list Anisotropic neighbor repulsion (Moussaid-Helbing 2009). Iterates over all neighbors within ``neighbor_range`` and sums their contribution. .. py:method:: obstacle_force() -> list Exponential repulsion summed over all nearby line obstacles. The upstream reference uses only the single nearest obstacle, which oscillates in symmetric environments (two parallel walls flip which one is "nearest" each step). We use the Helbing-Molnar (1995) summation form instead: every segment within ``5 * sigma_obstacle`` contributes an exponentially decayed push, so symmetric walls cancel and the agent walks the centreline. The integration is also clamped against overlap (``distance < 0`` would otherwise make ``exp(-distance/sigma)`` explode). .. py:data:: state_a :value: [0.0, 0.0, 1.0, 0.0, 0.3, 1.0, 0.0, 0.0]