Piper Method

Forces

Acceleration of a walking body is the sum of three terms, then clamped to ±12 m/s²:

a=adrive+awall+apersona = a_{\mathrm{drive}} + a_{\mathrm{wall}} + a_{\mathrm{person}}

Held bodies (zone stop, attractor dwell) and bodies already on a conveyor contribute zero. A conveyor is an escalator or a fare gate: once boarded, kinematics replace this sum.

Driving

The walker relaxes toward a desired velocity over time tau:

adrive=vdes heading−v−min⁡(0, v⋅heading) headingτa_{\mathrm{drive}} = \frac{v_{\mathrm{des}}\,\mathrm{heading} - v - \min(0,\, v\cdot\mathrm{heading})\,\mathrm{heading}}{\tau}

The extra term only acts when the walker is moving backward against its heading. That backward speed is undone twice as fast as any other speed error, so someone shoved back braces and steps forward again instead of drifting.

heading is the unit vector toward the current waypoint, then yawed by sight (below). v_des starts as the walker’s sampled desired speed, multiplied by the zone speed_factor when they stand in a zone. On a stair that factor is the grade reduction. On a conveyor it is replaced by the belt speed.

When the headway gap to someone in the same lane is under 0.18 m, tau becomes min(1.6 × tau, 0.85 s) so the queue brakes more gently. Viswalk’s default relaxation is 0.4 s; a queued body here sits at 0.64 s.

Speed after integration is capped at 1.8 * v_des (at least 0.35 m/s). A near-zero desired speed caps at 0.14 m/s so a stopped body can still ease out. A walker who wants to move (v_des ≥ 0.08) also can't go backward along its heading faster than 0.2 m/s (BACK_MAX). A shove can still slow them, stop them or push them sideways, but it can't send them sliding back.

People

Person repulsion uses the nearest eight neighbours on the same floor or the same stair (REACT_TO_N, Viswalk’s ReactToN). Across a stair mouth, someone on the flight and someone on open floor count as neighbours when their drawn heights are within 0.6 m. Neighbours farther than ped_range are ignored. The gap is centre distance minus both radii.

w=λ+(1−λ)⋅0.5⋅(1+cos⁡ϕ)magnitude=w⋅ped_a⋅exp⁡(−gap/ped_b)\begin{aligned} w &= \lambda + (1 - \lambda)\cdot 0.5\cdot(1 + \cos\phi) \\ \mathrm{magnitude} &= w \cdot \mathit{ped\_a} \cdot \exp(-\mathrm{gap} / \mathit{ped\_b}) \end{aligned}

φ is the angle between the walker’s heading and the direction toward the neighbour. lambda is the anisotropy floor: people ahead weigh more than people behind. Johansson, Helbing and Shukla’s video fits give 0.06–0.16; the default here is 0.25, a little more weight on people behind.

A forward-only extra asoc_mean * exp(−gap / ped_b) is added when the neighbour is in front (cos φ > 0). Overlap (gap < 0) adds a linear contact term ped_k * (−gap).

Same-direction neighbours (alignment > 0.25 and in front) keep the lateral part of the push and drop any component that would shove the queue backward.

Oncoming neighbours (alignment below −0.25, in front, not yet touching) keep only 30% of the backward part of their push (OPPOSE_BACK). The rest becomes a sideways step away from them, at 0.6 times the removed amount (OPPOSE_SIDESTEP). The step goes to the cultural side when they are dead ahead. People coming the other way make walkers give way sideways rather than stopping them. Once bodies touch, the full push applies.

Members of one visitor group (see behaviours) replace all of this with a softer push between themselves: min(0.3 * ped_a * exp(−(gap − 0.3) / ped_b), ped_a), plus the contact term on overlap. They skip each other for headway and following.

Contact

The contact term alone is soft. In a jam, the drive and the crowd behind beat it, and bodies slide through one another. So bodies are also hard discs. At the end of each tick, any two walkers who can touch (same floor or flight, or across a stair mouth as above) and whose centres are closer than their two radii are pushed apart along the line between them, each by half the overlap. This applies to groupmates too. The pass sweeps all pairs up to 16 times (CONTACT_PASSES) and stops once no overlap deeper than 2 mm (CONTACT_SLOP) is left. In a packed jam about 1 cm can remain.

  • A walker held by a stop, a dwell or a pick-up, loitering, or on a conveyor does not move. The other body takes the whole push. A captured walker (at an attractor or a seat) is left out of the pass entirely.
  • A push never carries a body across a wall that applies to it (floor edge, hole, obstacle, or the side of the zone it stands in), or into a solid (solid_at). It slides along that wall instead, or, if that would cross another or enter the solid, the other body takes the push. A body that ended the pass inside a solid is put back, or ejected to the nearest walkable side if it began inside. A walker without a crossing pass is not pushed onto a crossing that is shut.
  • Velocity toward the push is dropped, so the bodies do not keep closing.

So a crowd compresses until bodies touch all round and no further. For 0.25 m bodies, that is about 4–4.6 ped/m² (square to hexagonal packing). The LOS G band starts there (outputs).

Headway

Desired speed is then limited by the collision-free headway (Tordeux, Chraibi, and Seyfried 2015, as used in JuPedSim; references):

vdes=min⁡(vdes, max⁡(0, (gap−0.08)/headway_t))v_{\mathrm{des}} = \min\bigl(v_{\mathrm{des}},\ \max(0,\ (\mathrm{gap} - 0.08) / \mathit{headway\_t})\bigr)

The gap counts only when the neighbour is ahead in a narrow lateral band (about 0.55 m). A person stuck off to the side does not stop the stream.

Sight and lanes

Sight is a cone of sight_m metres and sight_deg degrees. It rewrites the unit heading and leaves speed alone. It covers anyone within 3 m of the walker's drawn height, so the lower half of a flight is visible from its foot.

  • Opposing traffic (heading alignment below −0.25) yaws the walker toward the cultural side by up to lane_m. keep_left is the Singapore / Indonesia convention. Viswalk’s default side preference is 0, no preference.
  • Same-direction people pull the heading toward the side they already occupy. That pull stays off until follow_need same-direction people are in the cone, then grows with each extra person. One walker ahead is not a stream.
  • Both of those only count people inside a 1.6 m corridor each side of the walker's line (SIGHT_LANE). Someone walking several metres to the side is not in the walker's way. Before this limit, those people drove whole streams to the edges and left the middle of a wide street empty. The follow_need count still includes everyone in the cone.
  • Look-ahead avoidance. For each person in the cone, the closest approach is predicted from their velocity and the walker's own desired velocity. Suppose that approach falls within the next 3 s (AVOID_T) and they would pass closer than two radii plus 0.35 m (AVOID_CLEAR). The walker then turns away from where the other person will be, toward the cultural side when the miss is nearly dead centre (AVOID_TIE). Urgency grows as the meeting gets nearer and the miss gets closer. The summed urgency times 0.9 is a yaw, capped at ±0.6 rad (AVOID_GAIN, AVOID_YAW). This applies on top of the lane yaw above. The swerve happens seconds before any repulsion acts, so most head-on meetings never become a shove.
  • A separate short-range follow force tugs toward a point just behind the nearest same-direction neighbour, with the same follow_need gate, inside 4 m. Its strength is follow_a.

lane_m is deliberately small (default 0.4 m) so two-way flow stays one crowd. A large sidestep splits the walkway into two groups.

Walls

Walls are static segments: floor boundary, holes, obstacles, and the long sides of zones. The grid is rebuilt when the scenario changes, not every tick.

Within 1.5 m plus the body radius the push is exponential in the gap, with constants fixed in code (A = 5, B = 0.2 m, contact stiffness K = 40, cap 60 m/s²). Corners push from the point, not from the edge normal, so a walker beside a wall is not shoved along it from a distant corner. A walker on the solid side of an edge is pushed back out through it with a penetration term, but only when that edge is the nearest wall. The far faces of a column or obstacle face anyone standing just outside it from behind; they are ignored, otherwise they would pull that walker into the solid.

When the wall push fights the driving term (dot product negative and wall magnitude above 1.5), a tangent acceleration of 2.8 m/s² slides the walker along the wall toward the heading.

A stuck walker can mute the nearest hole or obstacle for 1.6 s and repath. That drops only the soft wall term; they still cannot step or be pushed into the solid. That is a recovery, not part of the force law.

Defaults

Scenario params override these. Clamps are the ranges apply_params accepts. The > 0 checks on tau and radius apply when a scenario is loaded; a live patch does not re-check them.

NameDefaultClampRole
tau0.4 smust be > 0Driving relaxation
lambda0.250–1Anisotropy floor
radius(required)must be > 0Body radius; harness starts at 0.25 m
ped_a1.150–8Person repulsion amplitude
ped_b0.2 m0.05–1.5Person falloff
ped_range0.45 m0.05–3Person cutoff
asoc_mean0.120–4Extra forward repulsion
ped_k100–80Overlap stiffness
sight_m11 m1–24Lane-choice range
sight_deg120°20–180Lane-choice cone
lane_m0.4 m0–3Opposing sidestep
follow_a1.20–6Tailgate pull
follow_need31–12Same-direction count before follow turns on
headway_t0.65 s0.05–3Time gap in the headway law
keep_lefttrue—Cultural side

Viswalk’s isotropic social amplitude (ASocIso 2.72) is stronger than ped_a 1.15. The softer default is intentional: the stronger value splits a two-way crowd.