MATLAB implementation of CLiFF-map — Circular-Linear Flow Field map — a
method for mapping the motion patterns of an environment from velocity
measurements (human tracking, anemometers, …). Given a set of velocity
observations, it builds a map of multimodal flow as a field of semi-wrapped
Gaussian mixtures over orientation
See the paper: T. P. Kucner et al., Enabling Flow Awareness for Mobile Robots in Partially Observable Environments, IEEE RA-L 2017 (Citation).
Note on AI assistance. The current (optimised) implementation and this documentation were produced with substantial help from an AI coding assistant (Anthropic Claude), under human direction and review. It is validated against the original implementation (now in
legacy/); review before use. See Development & AI use.
This repo now ships an optimised, parallel implementation at the top level;
the original implementation is preserved unchanged under
legacy/.
| Location | What | |
|---|---|---|
| Optimised (current) | top level | vectorised mean-shift / EM + parfor; functions below |
| Legacy (original) | legacy/ |
the original @Batch / @DynamicMap classes + drivers |
| File | Purpose |
|---|---|
bvn_pdf.m |
fast vectorised bivariate-normal density (replaces mvnpdf) |
cl_mle.m |
circular-linear MLE (mean + covariance) |
auto_bandwidth.m |
Silverman mean-shift bandwidth |
mean_shift_fast.m |
batched mean-shift initialisation (all points shifted at once) |
em_fast.m |
vectorised semi-wrapped Gaussian-mixture EM |
build_cliffmap.m |
grid + range search + parfor fit → the map struct |
wrapToPi.m, wrapTo2Pi.m |
angle-wrap shims (so the Mapping Toolbox is not required) |
demo_synthetic.m |
self-contained demo (no external data) |
% self-contained synthetic demo
run('demo_synthetic.m')
% on your own data: position (Nx2 [x y]), theta_rho (Nx2 [theta rho])
gridp = [min(x) max(x) min(y) max(y) step]; % grid extent + spacing
M = build_cliffmap(position, theta_rho, timestamp, radius, gridp, wind, true); % true = parfor
% M.means{k} (Kx2), M.covs{k} (2x2xK), M.weights{k} (Kx1) per grid node k
% M.motion_prob, M.obs_ratio (p-bar, q-bar); M.grid, M.grid_shape, M.timeSet use_parfor = false (7th argument) for serial execution; pass an 8th
argument to cap points-per-location on very dense data.
The original mean-shift loops over every point with mvnpdf; the optimised
version shifts all points simultaneously with a closed-form bivariate kernel and
parallelises the per-location fits with parfor. On representative pedestrian
data this is several times faster, and the full-scale dataset is only practical
with the optimised version.
The optimised implementation is validated against the legacy one: on identical data the per-location mixture means agree to ~1e-8 (median) on ~93% of locations; the remaining few differ only at borderline cases (greedy mean-shift order / sharp EM pruning). A four-way cross-check (this MATLAB pair vs. a Python port) is maintained separately.
MATLAB with the Statistics and Machine Learning Toolbox (rangesearch) and,
for parfor, the Parallel Computing Toolbox. The Mapping Toolbox is not
required (wrap shims included).
The original implementation is unchanged in legacy/ — including the
@Batch / @DynamicMap classes, the pedestrian/air drivers, WangDivergence,
and the original README. Use it for reference or reproduction of earlier
results.
The optimised re-implementation and documentation were developed with substantial assistance from an AI coding assistant (Anthropic Claude) under human direction and review. Correctness is established by cross-validation against the legacy implementation. Review AI-generated code before use in academic or production contexts.
@article{kucner2017cliff,
title = {Enabling Flow Awareness for Mobile Robots in Partially Observable Environments},
author = {Kucner, Tomasz Piotr and Magnusson, Martin and Schaffernicht, Erik
and Hernandez Bennetts, Victor and Lilienthal, Achim J.},
journal = {IEEE Robotics and Automation Letters},
volume = {2}, number = {2}, pages = {1093--1100}, year = {2017},
doi = {10.1109/LRA.2017.2660060}
}