Files
Mujoco_WASM/python/mujoco/sysid

System Identification Toolbox

Given a MuJoCo model and recorded sensor data, find parameters that make simulation match reality. By default, the library uses nonlinear least-squares with box constraints to minimize the difference between measured and simulated (predicted) outputs. Residuals can be modified by static or optimized parameters, such as weights and time-delays.

The optimizer uses Gauss-Newton with finite-difference Jacobians. Each parameter perturbation requires an independent simulation rollout. All of them execute in a single batched call to mujoco.rollout, parallelized across threads.

Pipeline

You provide:

  • One or more ModelSequences each bundling a single MjSpec with one or more sequences of measured data. All will be optimized jointly.
  • A ParameterDict defining differentiable Parameter's with bounds.
  • Callbacks to apply Parameter's to an MjSpec (individually or jointly)
  • (optional) Functions (build_model, custom_rollout, modify_residual) that override the default residual function behaviour.

The framework:

  • build_residual_fn which composes user code in ModelSequences and overrides
  • Optimizes (optimize) the residual function returned by build_residual_fn
  • Optimizes parameters via batched parallel rollouts (optimize).
  • Saves results and generates an HTML report (save_results, default_report).

What Can You Identify?

You can optimize any parameter that differentiably modifies the final residuals. Common use cases include:

Physics parameters settable on MjSpec. Most parameters in MjSpec can be easily set directly by the user provided callbacks:

Target Approach
Contact sliding friction spec.pair("cp").friction[0] = p.value[0]
Joint damping spec.joint("j1").damping = p.value[0]

Convenience functions are provided for common system identification parameterizations that cannot be trivially appled to an MjSpec:

Target Approach
Body mass body_inertia_param(..., InertiaType.Mass)
Body mass + center of mass body_inertia_param(..., InertiaType.MassIpos)
Full inertia (10-D) body_inertia_param(..., InertiaType.Pseudo)
Actuator P/D gains apply_pdgain(spec, "act1", p.value)

Full inertia uses the pseudo-inertia Cholesky parameterization (Rucker & Wensing 2022), guaranteeing physical consistency without singularities.

Measurement parameters such as sensor delays, gains, and biases are properties of the measurement system, not the physics model. The library provides utilities for applying these corrections to the residual after rollout, they are functionally complete but their API is not yet final.

Example

import mujoco
from mujoco import sysid

# 1. Load model and define parameters.
spec = mujoco.MjSpec.from_file("robot.xml")
model = spec.compile()

def set_link1_mass(spec, p):
    spec.body("link1").mass = p.value[0]

params = sysid.ParameterDict()
params.add(sysid.Parameter(
    "link1_mass", nominal=2.0, min_value=0.5, max_value=5.0,
    modifier=set_link1_mass))

# 2. Load and package measured data.
# arrays assumed to be in MuJoCo order, otherwise pass names argument
control = sysid.TimeSeries.from_control_names(times, ctrl_array, model)
measureddata = sysid.TimeSeries.from_names(times, measurement_array, model)
initial_state = sysid.create_initial_state(model, qpos_0, qvel_0)
ms = sysid.ModelSequences("robot", spec, "traj_1", initial_state, control, measureddata)

# 3. Build residual, optimize, save.
residual_fn = sysid.build_residual_fn(models_sequences=[ms])
opt_params, opt_result = sysid.optimize(initial_params=params, residual_fn=residual_fn)
sysid.save_results("results/", [ms], params, opt_params, opt_result, residual_fn)

default_report generates an interactive HTML report with videos, measurement comparisons, parameter tables, and confidence intervals.