sm::random_walk

A correlated random walk, following a bee flight model

import sm.random_walk;

Module file: sm/random_walk.cppm

Table of Contents

Summary

sm::random_walk<T> implements the random-walk generation model described in Stone, T. et al. (2017), “An Anatomically Constrained Model for Path Integration in the Bee Brain”, Current Biology 27, 3069-3085 (DOI: 10.1016/j.cub.2017.08.052).

random_walk generates a 2D path with the kind of statistics seen in real foraging-insect flight: a slowly-varying forward acceleration combined with a correlated (rather than fully random) turning angle, so the path curves smoothly rather than jittering back and forth. At each step, a random angular acceleration is drawn from a von Mises distribution (its concentration parameter kappa controls the ‘wiggliness’ of the path). A separately generated, smoothly-varying linear acceleration profile drives the walker’s forward speed.

Creating a walk

sm::random_walk<float> rw (500u, 50u);              // n_steps, a_tau
sm::random_walk<float> rw2 (500u, 50u, T{50});      // ...and kappa (von Mises concentration)
sm::random_walk<float> rw3 (500u, 50u, T{50}, T{0.01}); // ...and acc_max (peak acceleration)

n_steps is how many steps generate (below) will produce. a_tau controls how often the underlying acceleration profile changes: a fresh random acceleration value is drawn every a_tau steps, then smoothed across those steps with a cubic spline (see Acceleration profile, below) so the forward acceleration varies gradually rather than jumping. kappa is the von Mises concentration parameter for the angular-acceleration draws (default 100; higher values give straighter, less-wandering paths). acc_max sets the upper end of the uniform distribution the acceleration profile is drawn from - the default interval is [0, 0.005].

Generating a path

sm::vvec<sm::vec<float, 2>> path = rw.generate(); // starting at theta=0, position=(0,0)
// or from a given heading/position:
sm::vvec<sm::vec<float, 2>> path2 = rw.generate (theta0, start_position);

generate returns n_steps coordinates, calling step() internally once per coordinate. You can also call step() yourself if you want to inspect the walker’s state (theta, omega, velocity, speed) between steps, and about_turn() to add a half-turn (pi radians) onto the current heading.

reset() zeroes t, theta, omega, velocity and speed, but does not regenerate the acceleration profile a or the von Mises random number generator - call init() again (which does both, plus reapplying n_steps/a_tau) if you want a genuinely fresh walk rather than just restarting the clock on the existing one.

Acceleration profile

At construction, init() draws n_steps / a_tau random values (uniformly, then scaled into [0, acc_max]) and expands them with cubic_spline_expansion (see below) into the member a, which step() reads one element at a time as it advances.

Note: the expanded a ends up with (n_steps / a_tau) * (a_tau + 1) elements, which generally isn’t exactly n_steps: for n_steps=500, a_tau=50, a.size() comes out as 510, not 500. This is harmless for random_walk itself (step() guards its lookup with if (t < this->a.size())), but is worth knowing if you inspect a directly.

This page was authored with AI, based on human written code in random_walk.cppm and reviewed by Seb James.


This site uses Just the Docs, a documentation theme for Jekyll.