gait_analysis
Foot-contact event detection, gait cycles, and locomotion metrics.
Gait analysis for walking mechanism simulations.
Transforms raw joint trajectory data (loci) into biomechanics metrics: duty factor, stride frequency, phase offsets between feet, foot trajectory shape analysis, and gait cycle decomposition.
Example:
from leggedsnake.gait_analysis import analyze_gait
# After running a simulation with record_loci=True
result = fitness(topology, dimensions)
gait = analyze_gait(
loci=result.loci,
foot_ids=walker.get_feet(),
dt=0.02,
)
print(gait.mean_duty_factor, gait.mean_stride_frequency)
print(gait.phase_offsets)
- class leggedsnake.gait_analysis.FootEvent(foot_id: str, time: float, event_type: Literal['touchdown', 'liftoff'], position: tuple[float, float])
Bases:
objectA single foot touchdown or liftoff event.
- __init__(foot_id: str, time: float, event_type: Literal['touchdown', 'liftoff'], position: tuple[float, float]) None
- event_type: Literal['touchdown', 'liftoff']
- foot_id: str
- position: tuple[float, float]
- time: float
- class leggedsnake.gait_analysis.GaitAnalysisResult(foot_events: list[FootEvent] = <factory>, gait_cycles: dict[str, list[GaitCycle]] = <factory>, foot_trajectories: dict[str, list[tuple[float, float]]] = <factory>, stability: StabilityTimeSeries | None = None, dt: float = 0.02)
Bases:
objectComplete gait analysis for a simulation run.
- Variables:
foot_events (list[FootEvent]) – All detected touchdown/liftoff events.
gait_cycles (dict[str, list[GaitCycle]]) – Stride cycles keyed by foot ID.
foot_trajectories (dict[str, list[tuple[float, float]]]) – Raw foot trajectories keyed by foot ID.
stability (StabilityTimeSeries | None) – Stability data if available.
dt (float) – Simulation timestep used.
- __init__(foot_events: list[FootEvent] = <factory>, gait_cycles: dict[str, list[GaitCycle]] = <factory>, foot_trajectories: dict[str, list[tuple[float, float]]] = <factory>, stability: StabilityTimeSeries | None = None, dt: float = 0.02) None
- dt: float = 0.02
- energy_per_cycle(total_energy: float) float
Mean dissipated energy per stride cycle.
- Parameters:
total_energy (float) – Energy accumulated over the full simulation (from
_SimulationResult.total_energyor equivalent).- Returns:
total_energy / total_cyclesaveraged across feet. Returns 0 when no complete cycles were detected.- Return type:
float
- foot_trajectories: dict[str, list[tuple[float, float]]]
- property gait_asymmetry: float
Dispersion of duty factors across feet.
Population standard deviation of the per-foot mean duty factor. Zero when every foot spends the same fraction of its cycle in stance; larger when some legs drag and others rush.
- property mean_duty_factor: float
Average duty factor across all feet and cycles.
- property mean_stride_frequency: float
Average stride frequency in Hz across all feet.
- property mean_stride_length: float
Average horizontal distance between consecutive touchdowns.
- property phase_offsets: dict[tuple[str, str], float]
Phase difference between each pair of feet.
Normalized to [0, 1) where 0 = in-phase, 0.5 = alternating.
- stability: StabilityTimeSeries | None = None
- summary_metrics() dict[str, float]
Flat dictionary of all scalar gait metrics.
- property total_cycles: int
Total number of complete stride cycles across all feet.
- class leggedsnake.gait_analysis.GaitCycle(foot_id: str, stance_start: float, stance_end: float, swing_start: float, swing_end: float)
Bases:
objectMetrics for one stride cycle of a single foot.
- __init__(foot_id: str, stance_start: float, stance_end: float, swing_start: float, swing_end: float) None
- property duty_factor: float
- foot_id: str
- property stance_duration: float
- stance_end: float
- stance_start: float
- property stride_period: float
- property swing_duration: float
- swing_end: float
- swing_start: float
- leggedsnake.gait_analysis.analyze_gait(loci: dict[str, list[tuple[float, float]]], foot_ids: list[str], stability: StabilityTimeSeries | None = None, dt: float = 0.02, contact_threshold: float = 0.1) GaitAnalysisResult
One-call gait analysis from simulation loci.
- Parameters:
loci (dict[str, list[tuple[float, float]]]) – Joint trajectories keyed by node ID (from
FitnessResult.loci).foot_ids (list[str]) – Node IDs of feet (from
Walker.get_feet()).stability (StabilityTimeSeries | None) – Optional stability data to attach.
dt (float) – Simulation timestep.
contact_threshold (float) – Maximum y-coordinate for ground contact detection.
- Return type:
- leggedsnake.gait_analysis.compute_cost_of_transport(energy: float, mass: float, distance: float) float
Mechanical cost of transport
COT = E / (m · d).Standard locomotion-efficiency metric — lower is better. The energy
Eshould be the total mechanical work done by the motors over the run;mthe walker mass;dthe forward distance travelled. Dimensionless whenEis in Joules,min kg,din metres (units cancel throughgimplicitly when divided by gravity, but the unitful formJ/(kg·m)is what most biomechanics papers report).- Parameters:
energy (float) – Total energy spent (Joules).
mass (float) – Walker mass (kg).
distance (float) – Forward distance travelled (m).
- Returns:
E / (m · d)— or0.0when mass or distance is non-positive.- Return type:
float
- leggedsnake.gait_analysis.compute_foot_trajectory_metrics(trajectory: list[tuple[float, float]]) dict[str, float]
Per-foot trajectory shape metrics.
- Parameters:
trajectory (list[tuple[float, float]]) – A single foot’s (x, y) trajectory.
- Returns:
max_height,horizontal_range,path_length,smoothness(inverse mean curvature).- Return type:
dict[str, float]
- leggedsnake.gait_analysis.compute_froude_number(speed: float, gravity: float, leg_length: float) float
Walking Froude number
Fr = v² / (g · L).Dimensionless gait metric introduced for ship hulls (William Froude) and brought to locomotion by R. McNeill Alexander. Lets walkers of very different sizes be compared directly: the walk-to-run gait transition occurs near
Fr ≈ 0.5across the animal kingdom.- Parameters:
speed (float) – Mean forward speed (m/s).
gravity (float) – Magnitude of gravitational acceleration (m/s², positive).
leg_length (float) – Characteristic length — typically hip height or, for arbitrary planar topologies, the linkage’s vertical extent.
- Returns:
v² / (g · L)— or0.0when gravity or leg length is non-positive.- Return type:
float
- leggedsnake.gait_analysis.compute_phase_offsets(cycles: dict[str, list[GaitCycle]]) dict[tuple[str, str], float]
Phase difference between each pair of feet.
Compares the mean stance_start times, normalized by the mean stride period. Result is in [0, 1) where 0 = in-phase, 0.5 = alternating.
- Parameters:
cycles (dict[str, list[GaitCycle]]) – Gait cycles keyed by foot ID.
- Returns:
Phase offset for each foot pair.
- Return type:
dict[tuple[str, str], float]
- leggedsnake.gait_analysis.detect_foot_events(foot_trajectories: dict[str, list[tuple[float, float]]], contact_threshold: float = 0.1, dt: float = 0.02) list[FootEvent]
Detect touchdown/liftoff events from foot y-position threshold crossings.
A touchdown occurs when the foot y-coordinate drops below
contact_threshold. A liftoff occurs when it rises back above.- Parameters:
foot_trajectories (dict[str, list[tuple[float, float]]]) – Foot trajectories keyed by foot ID, each a list of (x, y) points.
contact_threshold (float) – Maximum y-coordinate for ground contact.
dt (float) – Timestep between trajectory points.
- Returns:
Chronologically sorted events across all feet.
- Return type:
list[FootEvent]