pybounds

pybounds

Python implementation of BOUNDS: Bounding Observability for Uncertain Nonlinear Dynamic Systems.

PyPI version Tests Coverage Docs

Introduction

This repository provides python code to empirically calculate the observability level of individual states for a nonlinear (partially observable) system, and accounts for sensor noise. Below is a graphical example of how pybounds can discover active sensing motifs. Minimal working examples are described below.

Installing

The package can be installed from PyPi:

pip install pybounds

or from source, for development, after cloning the repo:

pip install -e .

Quick Start

To demonstrate pybounds with a simple example we use a downward-pointing camera moving horizontally with acceleration that is controlled directly with control inputs (u). The two states are ground speed g and (constant) altitude d, and the only measurement is the ventral optic flow ratio r = g/d. We use pybounds to understand when g and d are observable.

See notebooks in next section for more detailed usage examples.

import numpy as np
import matplotlib.pyplot as plt
import pybounds

# 1. Define continuous time system dynamics f(X, U) and measurement h(X, U)
def f(X, U):         # states: gap g, distance d — input u drives g
    return [U[0], 0] # returns: d/dt(g), d/dt(d) 

def h(X, U):        # monocular camera measures the g/d ratio
    return [X[0] / X[1]]

# 2. Simulate a trajectory
sim = pybounds.Simulator(f, h, dt=0.01,
                         state_names=['g', 'd'], input_names=['u'],
                         measurement_names=['r'])
t, x, u, _ = sim.simulate(x0={'g': 2.0, 'd': 3.0},
                           u={'u': 0.1 * np.ones(500)},
                           return_full_output=True)

# 3. Compute sliding-window observability and Fisher information
ev = pybounds.compute_observability(sim, t, x, u, R={'r': 0.1})

# 4. Plot minimum error variance over time for each state
ev.set_index('time')[['g', 'd']].plot(logy=True, ylabel='Min. error variance')
plt.show()

Notebook examples

Basic Examples

These notebooks provide a more detailed example of pybounds functionality including:

  • How to use model predictive control to drive systems along specified trajectories

  • Demonstration of what happens inside the pybounds.compute_observability wrapper function, allowing for detailed investigations of the observability calculations

Examples using pybounds with continuous time dynamics, see these notebook examples:

JAX Accelerated Examples

pybounds includes a JAX backend (JaxSimulator, JaxSlidingEmpiricalObservabilityMatrix) that replaces the numerical finite-difference Jacobian with exact autodiff via jax.vmap + jax.jacfwd. The simulation and all downstream analysis (Fisher information, plotting) are unchanged.

When JAX helps most: the speedup scales with the number of sliding windows. Short trajectories with few windows see modest gains; long trajectories benefit dramatically.

System

States

Windows

Legacy

JAX (hot)

Speedup

Mono-camera

2

895

~21 s

~1.1 s

~19×

Fly-wind

18

37

~6 s

~2.6 s

~2.4×

To use the JAX backend, install JAX and rewrite your dynamics f and measurement h using jax.numpy instead of numpy. See the notebooks below for worked examples.

Using a Custom Simulator

This has received the least development, however, a working tutorial can be found here.

Citation

If you use the code or methods from this package, please cite the following paper:

Cellini, B., Boyacioglu, B., Lopez, A., & van Breugel, F. (2025). Discovering and exploiting active sensing motifs for estimation (arXiv:2511.08766). arXiv. https://arxiv.org/abs/2511.08766

Additional resources

To learn more about nonlinear observability, its relation to Fisher information, see Boyacioglu and van Breugel

To start with the basics, check out these open source course materials: Nonlinear and Data Driven Estimation.

License

This project utilizes the MIT LICENSE. 100% open-source, feel free to utilize the code however you like.

Reference