Skip to main content

best-linear-approximation

A well-tested Python package for estimating the nonparametric best linear approximation (BLA) and its uncertainty estimates for multivariable nonlinear systems in open- and closed-loop settings.

The implemented definitions follow System Identification: A Frequency Domain Approach, Second Edition by Rik Pintelon and Johan Schoukens, particularly the robust methods in Section 4.3.1.

Basic usage

The four available BLA estimation methods correspond to different experimental conditions. They estimate the equivalent nonlinear system from input $u$ to output $y$ under periodic multisine excitation. The diagrams below show the input-output signals and measurement-noise sources $v_u$ and $v_y$; see each method's docstring for its required arguments.

Known input

Use this method when $u$ is known exactly. The BLA then captures all dynamics between $u$ and $y$, including actuator dynamics, delays, zero-order-hold effects, etc. Including this behavior is often desirable for control applications.

Known-input measurement setup

Function: best_linear_approximation.robust.known_input(...)

Noisy input

To identify only the system dynamics, use a measurement of the signal entering the system as $u$. Since $u$ is then a noise-corrupted measurement of the true system input, the BLA estimate will be biased. The bias may be acceptable when the input measurements are sufficiently clean, possibly after averaging over repeated periods.

Noisy-input measurement setup

Function: best_linear_approximation.robust.noisy_input(...)

Known reference

As in the noisy-input case, use a measurement of the signal entering the system as $u$, but now also use a clean reference $r$. Treating $r$ as an instrumental variable reduces the effect of input measurement noise on the BLA estimate and allows actuator-induced nonlinear distortion at the system input to be quantified.

Known-reference measurement setup

Function: best_linear_approximation.robust.known_reference(...)

Closed loop

Closed-loop estimation uses the same instrumental-variable principle as the known-reference method. Using a clean reference avoids the bias that generally arises when applying an open-loop method to closed-loop data. This reference can be the output reference $r_1$ or an additive input reference $r_2$. It must have the same number of channels as $u$: this is guaranteed for $r_2$, but must be verified for $r_1$ in multivariable settings.

The diagram below does not show an actuator. Depending on the desired model scope, it can be placed between $r_2$ and $u$ to exclude its dynamics from the BLA, or between $u$ and the system to include them.

Closed-loop measurement setup

Function: best_linear_approximation.robust.closed_loop(...)

Result object

The above estimation methods return a NonparametricBLA object:

NonparametricBLA
├── G: FrequencyResponse
│   ├── value
│   └── noise, nonlinear, total: Uncertainty
├── spectra: Spectra
│   ├── U: InputSpectrum
│   │   ├── value
│   │   └── noise, nonlinear, total: Uncertainty
│   ├── Y: OutputSpectrum
│   │   ├── value
│   │   └── noise, nonlinear, total, total_equation_error: Uncertainty
│   └── R: InputSpectrum | None
│       └── value
├── freq: FrequencyInfo
└── experiment: ExperimentInfo

Each available uncertainty field is an Uncertainty object:

Uncertainty
├── cov: ComplexArray | None              (n_bins, n_channels, n_channels), joint covariance
├── var: RealArray | None                 (n_bins, *marginal_shape), marginal variance
├── std: RealArray | None                 (n_bins, *marginal_shape), marginal standard deviation
├── as_percentage: RealArray | None       uncertainty RMS relative to "value" RMS, in %
└── as_power_ratio_db: RealArray | None   "value" RMS relative to uncertainty RMS, in dB

Here, marginal_shape is the shape of the estimated quantity at a single frequency bin, and n_channels is the product of its dimensions. For example, a frequency response has marginal_shape = (ny, nu) and n_channels = ny * nu.

Input and output spectra and their noise uncertainties are returned at every frequency bin. All other values and uncertainties are returned only at excited frequency bins. When an uncertainty cannot be estimated from the available measurements, its properties are None.

as_percentage and as_power_ratio_db reduce the frequency axis, yielding useful summary statistics. For example, bla_estimate.spectra.Y.noise.as_power_ratio_db gives the signal-to-noise ratio for each output channel. The corresponding as_percentage gives an a priori, noise-imposed lower bound on the achievable simulation error of a nonlinear parametric model under the measured operating condition.

Benchmark datasets

For convenient access to selected benchmark datasets from nonlinearbenchmark.org, the package provides best_linear_approximation.dataloader, which loads and prepares multisine data in the format required by the BLA estimators.

The following benchmarks are included:

  • F-16 aircraft; load_f16()
  • Fine Steering Mirror; load_fine_steering_mirror()
  • Parallel Wiener-Hammerstein; load_parallel_wiener_hammerstein()
  • Silverbox; load_silverbox()

Example

import best_linear_approximation as bla

data = bla.dataloader.load_fine_steering_mirror()["train 300mV"]

bla_estimate = bla.robust.noisy_input(data.u, data.y, data.fs)

The above call automatically detects the excited frequency bins from data.u. Alternatively, if the bins are known, they can be passed as the fourth argument to noisy_input(...).

Additional examples and visualizations of nonlinear benchmark systems are available in examples/.

Installation

Requires Python 3.12 or later. The only runtime dependency is NumPy (2.0 or later).

Install with pip:

pip install best-linear-approximation

Or add it to a uv project:

uv add best-linear-approximation

If you wish to use the benchmark dataloader, replace best-linear-approximation in either command with "best-linear-approximation[benchmarks]". This installs the additional required dependencies. Calling a benchmark loader will download its data to the local cache when it is not already available.

Looking for:

Metadata

Release files for best-linear-approximation 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for best-linear-approximation 0.1.0
File Size Uploaded Provenance
best_linear_approximation-0.1.0.tar.gz 25.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for best-linear-approximation 0.1.0
File Interpreter ABI Platform
best_linear_approximation-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 63.2 kB

Release files / best_linear_approximation-0.1.0.tar.gz

Download URL best_linear_approximation-0.1.0.tar.gz
Size 25.9 kB
Tags Source
SHA-256 checksum
How to use checksums
110296a4c524e279049c5168d02b49e707ee564cb331fb851d690aa55b0da597
BLAKE2b-256 checksum
How to use checksums
77333fcfbd556b388094077cbc99886ce305d2e48910cfb1a0b9fa72224f0e9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / best_linear_approximation-0.1.0-py3-none-any.whl

Download URL best_linear_approximation-0.1.0-py3-none-any.whl
Size 37.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
33a23bc18a99e0ed81acfe9b098272dad5051b4fa0c405773a647bb098188252
BLAKE2b-256 checksum
How to use checksums
433830d69915b85b337f315a02150de6663d0ccb7b700b95e8f25a22af939f79
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for best-linear-approximation 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page