Skip to main content

ROTA

Tests PyPI License: GPL v3+ Python 3.10–3.13 Dependencies: NumPy + SciPy

Rotational Order Tracking & Analysis. Rota is Latin for "wheel".

ROTA is a lightweight, open-source Python library for order analysis of noise and vibration signals from rotating machinery (engines, electric motors, gearboxes), with tools for order-based sound resynthesis. It depends only on NumPy and SciPy. The project rule is that each function is implemented independently from the published literature and tested on synthetic signals with known analytic ground truth.

The design document is ROADMAP.md.

Status

Pre-alpha. The current release is 0.4.0; functions and signatures may still change before 1.0.

Module Contents Since
rota.speed Tachometer pulses to rpm, rpm to shaft angle, control-signal cleanup and resampling, vehicle speed to rpm, steady-segment selection; tacholess speed estimation (order comb + dynamic programming, with confidence and search-boundary flags); virtual rpm. Later: signal alignment (v0.5) 0.1–0.4
rota.angle Resampling from uniform time to uniform shaft angle (computed order tracking) with angle-domain anti-aliasing; the inverse mapping; time warping to a reference speed (stationarize) 0.1, 0.3
rota.maps Rpm-frequency (Campbell) map, rpm-order map. Later: binning options (v0.5) 0.1
rota.slices Order spectrum, order slice. Later: frequency slice, overall level, metric versus rpm, order share (v0.5) 0.1
rota.extract Order extraction (second-generation Vold-Kalman filter, joint over orders and shafts; phase-locked tracked harmonics), order removal, residual, resolvability check 0.2
rota.resynth Order tables (explicit peak/RMS), additive order synthesis offline and in blocks, broadband synthesis without frame-rate pumping, order editing, speed remapping, order-plus-residual recombination, steady listening excerpts, provenance sidecars 0.3
rota.synth Speed profiles and run-up signals with analytic ground truth; tone-plus-noise listening stimuli; realistic scenarios (engine run-up, electric drive, cruise) with transfer paths, background noise and recorder impairments 0.1, 0.3, 0.4
rota.metrics Speed-track error, waveform similarity (energy-weighted), residual order energy, window and pumping checks, envelope statistics 0.1–0.3
rota.tonal Thin bridge to open-source psychoacoustic tools: calibrated level, resampling, order prominence v0.5 (planned)
rota.plot Plotting helpers, kept separate from computation v0.5 (planned)

Planned for v1.0: full validation report, complete documentation, Zenodo DOI.

Out of scope: real-time audio I/O, GUI, rotor-dynamics analysis (orbits, Bode plots), spatial audio, reading proprietary file formats, and the psychoacoustic metrics themselves (loudness, sharpness, roughness, tonality).

Installation

Python 3.10 or later, NumPy 1.23 or later, SciPy 1.9 or later. From PyPI:

pip install rota-order

The distribution is called rota-order because the name rota is taken on PyPI; the import name is rota (import rota).

From source:

git clone https://github.com/ZhenxianLi/ROTA.git
cd ROTA
pip install -e .

To run the tests:

pip install -e ".[test]"
pytest

Matplotlib is an optional extra for rota.plot and the examples: pip install -e ".[plot]".

Quick start

A synthetic run-up from 1000 to 4000 rpm containing a single order, analysed with an order-rpm map. Because the signal comes from rota.synth, the result can be compared with the known amplitude.

import numpy as np
import rota

fs = 16000.0                              # sampling rate, Hz
t = np.arange(int(10 * fs)) / fs          # time, s

# Linear speed ramp in rpm, and a signal with one order (order 2, amplitude 1.0)
rpm = rota.synth.rpm_profiles(t, "linear", start=1000, stop=4000)
sig = rota.synth.synth_runup(fs, rpm, orders=[{"order": 2, "amplitude": 1.0}], seed=0)
# sig.x: signal, sig.rpm: speed in rpm

# Order-rpm map with 0.25 order resolution, amplitudes as RMS
m = rota.maps.rpm_order_map(sig.x, fs, sig.rpm, order_resolution=0.25, amplitude="rms")

# Amplitude of order 2 as a function of speed
s = rota.slices.order_slice(m, 2)
# s.rpm: speed in rpm, s.amplitude: order amplitude (RMS, as selected for the map)

The amplitude convention of every function is stated in its docstring.

Examples

Six scripts in examples/ cover order maps and slices, tachometer and tacholess speed, order extraction and removal, order-table resynthesis, and two complete synthetic recordings that you can listen to, an engine run-up and an electric drive. Each builds its signal with rota.synth and prints its results against the known truth.

Campbell diagram, order map, engine speed and firing-order level of a synthetic engine run-up

A synthetic four-cylinder engine run-up from rota.synth.synth_scenario("ice_runup"): launch from idle with clutch slip, two upshifts, combustion bursts, a modal transfer path, engine broadband, road noise and rumble, two receiver channels. Campbell diagram and order map, the speed from the tachometer against the truth, and the level of the firing order against the truth at the receiver, before and after remove_orders (examples/05_realistic_engine_audio.py).

Listen

The recordings below are synthetic (no measured data) and are written by examples/05_realistic_engine_audio.py and examples/06_electric_drive_audio.py: 16-bit WAV at 32 kHz, all with the same scaling (4 Pa is digital full scale), so levels can be compared between files.

Tacholess speed

rota.speed.rpm_from_ridge estimates the speed from the signal alone with a comb of orders and a dynamic-programming ridge. Give it the orders the machine shows: the comb, not the data, decides between a speed and its octaves. For a four-stroke engine with N cylinders the firing order N/2 and its harmonics dominate, so use orders=(2, 4, 6) for four cylinders (the default (1, 2, 3, 4) then reads twice the crankshaft speed), (1.5, 3, 4.5) for three and (3, 6, 9) for six. Set rpm_range from a priori knowledge (idle speed to redline). The window adapts to the sweep by default (window="auto": 0.4 s, shorter for fast run-ups), and several channels are combined by averaging their power spectra. Each result carries a per-frame confidence (near 1 on a clean correct track, near 0 in noise) and a quality summary (median confidence, fraction of frames at a search bound, fraction of jumping frames, octave scores); a RidgeQualityWarning is issued when the track as a whole is likely wrong.

Conventions

  • Units. Time in s, sampling rate and frequency in Hz, rotational speed in rev/min (rpm), shaft angle in revolutions, order in cycles per revolution, vehicle speed in km/h.
  • Arrays. Signals have shape (n,) or (n, ch). Every operator acts on each channel independently and linearly, so amplitude and phase relations between channels are preserved.
  • Amplitude. Peak or RMS is always stated in the docstring and, where there is a choice, selected by an explicit amplitude argument ("peak" or "rms").
  • No hidden constants. Gains, calibration factors and reference pressures are passed explicitly. They are never built into a function.
  • Randomness. Every random process takes a numpy.random.Generator or an integer seed.
  • Estimators. Functions that estimate quantities (speed, order amplitude) are meant to return a confidence and to report when a search boundary was reached.

Design principles

  1. Independent implementation: algorithms follow public literature only (see Independence statement).
  2. Verifiable: each function is tested on synthetic signals with known analytic ground truth.
  3. Transparent: docstrings give the literature, the amplitude definition and the units.
  4. Plain Python: snake_case functions, NumPy arrays as input and output, computation separate from plotting.
  5. Interoperable: results can be passed on to open-source psychoacoustic tools such as SQAT and MoSQITo. ROTA does not depend on them.
  6. Multichannel first: operators are linear per channel (see Conventions).
  7. Reproducible: seedable randomness, and planned JSON sidecar files recording the parameters of each resynthesis.
  8. No hidden constants.

Validation

Analytic ground truth from rota.synth is the first reference: every test signal comes with its true speed, shaft angle, and amplitude and phase of each order. A black-box comparison with MATLAB's documented public functions, all parameters explicit, is the second reference: it runs in CI (workflow matlab-reference, see validation/README.md) and compares physical quantities (speed curves, order amplitudes along a ridge, Vold-Kalman waveforms and bandwidth), not map cells; when the two disagree, the analytic truth decides. Its output stays in the workflow artifact and is not published in the repository until the licence terms are confirmed. Resynthesis is tested by round trip: synthesise, analyse, compare with the input table. Continuous integration runs pytest only.

The design document defines 14 validation signals (T1 to T14). Version 0.1 covers T1 (single order, constant amplitude, linear run-up), T2 (several orders, a fixed-frequency resonance, noise), T5 (multi-pulse tachometer with jitter and dropped pulses) and T14 (low-speed start from idle with orders half an order apart). Version 0.2 adds T3 (exponential run-down), T4 (crossing orders on two shafts), T6 (fast run-up), T8 (twin shafts 0.5–4 % apart), T10 (true speed outside the search range), T12 (order removal) and T13 (extraction error versus speed-reference error). Version 0.3 adds T9 (order table → synthesis → analysis → table round trip, tests/test_ordertable.py) and T11 (broadband synthesis: PSD accuracy and no frame-rate pumping, tests/test_broadband.py). Version 0.4 adds stress tests on realistic scenarios (validation/stress.md). Cases and measured results: validation/README.md.

Tolerances (the analytic column is enforced by the test suite; the black-box column is the target of the CI comparison):

Quantity Against analytic truth Against black-box reference
Speed, median relative error <= 0.1 % <= 0.1 %
Tacholess speed, fraction of frames within 3 % (steady or slowly rising) >= 90 % within 5 percentage points
Order amplitude, stationary segments <= 0.2 dB <= 0.5 dB
Order amplitude near a resonance <= 1 dB <= 1 dB
Order waveform correlation (edges removed) >= 0.99 >= 0.99
Vold-Kalman -3 dB bandwidth within 5 % of the set value within 5 %
Order-table round trip, amplitude (T9) <= 0.2 dB not compared
Remaining energy of a removed order in the residual (T12) <= -20 dB not compared
Frame-rate pumping of broadband synthesis (T11) <= 1 dB not compared

All rows of the analytic column are met by the current release; measured values are in validation/README.md.

Independence statement

ROTA is an independent academic project. It is not affiliated with, endorsed by, or supported by MathWorks or any commercial software vendor. MATLAB is a registered trademark of The MathWorks, Inc.

All algorithms are implemented from the published literature cited in each docstring, and ROTA reads no proprietary file formats.

License

ROTA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See LICENSE.

Citation

See CITATION.cff (GitHub shows it as "Cite this repository"). A Zenodo DOI is planned for v1.0.

Acknowledgements

ROTA is designed, implemented and maintained by Zhenxian Li. Claude (Anthropic) was used as an assistant during development.

Metadata

Release files for rota-order 0.4.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 rota-order 0.4.0
File Size Uploaded Provenance Actions
rota_order-0.4.0.tar.gz 387.8 kB With provenance Details for rota_order-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for rota-order 0.4.0
File Interpreter ABI Platform Actions
rota_order-0.4.0-py3-none-any.whl Python 3 none any Details for rota_order-0.4.0-py3-none-any.whl

Total release size: 606.4 kB

Release files / rota_order-0.4.0.tar.gz

Download URL rota_order-0.4.0.tar.gz
Size 387.8 kB
Tags Source
SHA-256 checksum
How to use checksums
101a52a7c67a77ec7d26a7fadf1f15b3681c3ddaa6f4abcdfd6e0f8e3b326e2d
BLAKE2b-256 checksum
How to use checksums
2f46ce10e8a86ccc581ee0f4803625eca0bd9fd83dacc3c918e879f995136b71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / rota_order-0.4.0-py3-none-any.whl

Download URL rota_order-0.4.0-py3-none-any.whl
Size 218.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
de9aeec6a8e7655ca08f82e4f2611fae0bb8f59d84c0c7bf66f5592bfaab4caf
BLAKE2b-256 checksum
How to use checksums
e06e111f9912d040a81dfc3eff8a749d0cbf549b6e77dd100e58a4371b934261
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for rota-order 0.4.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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for rota_order-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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