What Diffusion Can Teach a Biomechanical Model

What Diffusion Can Teach a Biomechanical Model
A hands-on look at using NVIDIA's Kimodo motion-diffusion model to synthesize rare gait patterns; and why the free per-frame foot-contact labels it hands back are the more interesting part for anyone training biomechanical models.

Clinical gait datasets have a structural blind spot: the patterns that matter most for a model to learn, pronounced limps, asymmetric stance timing, unusual compensations, are exactly the ones you can't manufacture on demand. You get what walks through the door. Rare presentations stay rare, no matter how good your pipeline is.

That's the problem synthetic motion generation is actually good at attacking. Not replacing real clinical data, nothing should replace ground truth measured off a real patient, but filling in the underrepresented corners of the distribution with plausible, labeled examples a model can still learn structure from.

We spent an afternoon testing whether NVIDIA's Kimodo is a credible tool for that job. Short answer: yes, and not for the reason we expected going in.

What Kimodo actually is

A motion generator, not a biomechanics tool

Kimodo is a kinematic motion diffusion model, trained by NVIDIA on roughly 700 hours of commercially-licensed optical motion capture. Given a text prompt and, optionally, a set of kinematic constraints (keyframes, end-effector positions, 2D paths), it generates 3D human or robot motion sequences. It has nothing to do with gait analysis specifically; it's a general-purpose motion generator that happens to be very good at walking, because walking is common in its training data.

The code is Apache 2.0; model weights ship under NVIDIA's open model license. It's a real, usable, openly available research tool, not an internal AICU system; worth being precise about, since it would be easy to assume otherwise from the name alone.

Full documentation, model variants, and the technical report live at research.nvidia.com/labs/sil/projects/kimodo.

The experiment

Asking for a limp

We gave Kimodo's SOMA skeleton model (77 joints, the full-detail variant) a single text prompt and let it generate a 4-second clip on a single consumer GPU:

# CPU text encoder keeps VRAM under ~3GB -- fits an 8GB card comfortably
TEXT_ENCODER_DEVICE=cpu kimodo_gen \
  "A person walks slowly with an asymmetric limp, spending
   noticeably longer in stance on their left leg than their right leg." \
  --duration 4 \
  --model Kimodo-SOMA-RP-v1.1 \
  --output ./limp_gait \
  --save_example_dir \
  --seed 42
Skeleton
SOMA-77
Duration
4.0s / 120f
Diffusion steps
100
GPU
RTX 2080S · 8GB

What came back

Kimodo's output is a NPZ of posed 3D joints, not a video we wrote a small matplotlib renderer to turn it into something you can actually look at. Worth admitting: our first pass at this rendered a figure the size of a pixel, because we assumed the wrong axis was "up." Kimodo's docs describe the coordinate system as Z-up, but the actual per-frame joint array reads as Y-up, a five-minute numeric check (frame-zero range on each axis, looking for the one that spans roughly 0–1.7m) sorted it out. Small detail, but it's the kind of thing that silently wrecks a render rather than crashing it, so it's worth checking rather than assuming.

0:00
/0:04

20-frame synthetic walk cycle, SOMA-77 skeleton, rendered side-on (camera locked perpendicular to the walking direction, re-centered on the root joint every frame). Green/orange strips underneath are left/right stance, decoded live from Kimodo's own foot-contact output as the clip plays.

What actually matters

The interesting output isn't the mesh, it's this array, sitting right there in the NPZ alongside the joints:

posed_joints     (120, 77, 3)  float32   3D joint positions per frame
foot_contacts    (120, 6)      bool      [L_heel, L_toe, L_toe, R_heel, R_toe, R_toe]
root_positions   (120, 3)      float32   pelvis trajectory through the scene

foot_contacts is a per-frame, per-side boolean contact label, which is most of the way to a touchdown/liftoff annotation already. Turning it into stance spans is a dozen lines:

def stance_spans(contact_mask, fps=30, min_frames=3):
    """Boolean contact mask -> list of stance durations (seconds).
    min_frames filters single-frame contact-detector noise -- real
    stance events don't resolve to 1/30s blips."""
    spans, start = [], None
    for i, in_contact in enumerate(contact_mask):
        if in_contact and start is None:
            start = i
        elif not in_contact and start is not None:
            if i - start >= min_frames:
                spans.append((i - start) / fps)
            start = None
    return spans

left  = foot_contacts[:, 0] | foot_contacts[:, 1]   # heel OR toe
right = foot_contacts[:, 3] | foot_contacts[:, 4]

l_spans, r_spans = stance_spans(left), stance_spans(right)

On this specific clip, that gave three clean left-stance events and four right-stance events:

MEAN STANCE DURATION · CLEANLY-DETECTED CYCLES ONLY
LEFT
0.633s
RIGHT
0.592s
3 left-stance / 4 right-stance events over 120 frames. Left stance ran ~7% longer than right; modest, but in the direction the prompt actually asked for.
That ~7% is worth being honest about, in both directions. It's real signal: the model didn't just generate a generic walk, it produced a measurably asymmetric one, and the asymmetry landed on the side we named. It's also modest and noisy at the single-clip level, a few of the raw contact transitions were single-frame blips we had to filter out, and a different seed would almost certainly land on a different number. Text conditioning gets you directionally plausible variation, not a dialed-in biomechanical parameter. For augmentation where you actually need a specific stance-time ratio or a specific stride asymmetry, Kimodo's constraint conditioning (keyframes, end-effector paths) is the more precise lever to pull than the text prompt alone; a natural next experiment, not something this pass tested.

An augmentation channel, not a ground-truth replacement

  • What it's good for: cheaply generating labeled, structurally-plausible motion for the sparse tails of a training distribution, gait patterns that are individually rare but collectively make up a meaningful share of what a deployed model has to handle correctly.
  • What it isn't: a source of clinical ground truth. Kimodo has no notion of what a specific pathology actually looks like biomechanically, it knows what "limp" tends to look like across its training distribution of captured human motion, which is a different and weaker claim. Any model trained partly on synthetic sequences like these still needs its real accuracy numbers validated against real patient data, not synthetic data grading its own homework.
  • The more precise path: constraint-driven generation (foot-position keyframes, explicit stance-time targets) rather than text prompts alone, for anyone who needs a specific quantitative gait parameter rather than a plausible-looking one.

An open thread, not a shipped pipeline

This was a single afternoon's exploration, not a production augmentation pipeline, we wanted to know whether the idea holds up before investing further, and it does: a genuinely useful signal (per-frame, per-side contact labels) came back essentially for free, attached to a motion we didn't have to send a camera crew or a patient to go capture. The natural next step is constraint-conditioned generation against real quantitative targets, and a real ablation on whether a touchdown/liftoff detector trained with a slice of synthetic data actually generalizes better on rare real-world presentations; not just whether the synthetic clips look right to a human watching them.