pyoxynet
The open-source models from the Oxynet research papers, for cardiopulmonary exercise test (CPET) data. Give pyoxynet a test and it returns, second by second, the model's output for the moderate, heavy and severe exercise-intensity domains, and the two ventilatory thresholds (VT1 and VT2) where those outputs cross. It can also generate synthetic tests.
Everything runs on your machine. The models are frozen LiteRT files, so TensorFlow is not needed.
Install
pip install pyoxynet
Python 3.10 to 3.14, on Windows, Linux and macOS (Apple silicon).
Quick start
import pyoxynet
# The bundled example test, through the default model
out_df, thresholds = pyoxynet.test_pyoxynet()
print(thresholds['VT1']['time'], round(thresholds['VT1']['VO2'])) # 372 2979
print(thresholds['VT2']['time'], round(thresholds['VT2']['VO2'])) # 550 3656
Each threshold gives its time (s) and the VO2, VE and HR there. out_df holds the three
domain outputs (p_md, p_hv, p_sv) over time, next to the signals.
Your own test
import pandas as pd
import pyoxynet
df = pd.read_csv('my_test.csv') # your test, with the columns below
out_df, thresholds = pyoxynet.test_pyoxynet(input_df=df)
The columns test_pyoxynet reads:
| Column | Signal |
|---|---|
time |
seconds from the start of the test |
VO2_I |
oxygen uptake |
VCO2_I |
carbon dioxide output |
VE_I |
minute ventilation |
PetO2_I |
end-tidal O2 |
PetCO2_I |
end-tidal CO2 |
HR_I |
heart rate, optional: it is only reported at the thresholds |
- Any sampling works, breath by breath included.
test_pyoxynetaverages the data into one-second bins and interpolates linearly between them. - Each signal is min-max scaled over the test before it reaches the model, so units do not change the domains. The VO2, VE and HR reported at each threshold are in your file's units.
- Other columns, text included, are ignored. From a cart export, rename its columns and turn its time into seconds: the docs show how. The hosted Oxynet API reads vendor exports directly.
test_pyoxynetraises aValueErrorthat says why when it cannot place consistent thresholds: the outputs never cross, VT1 would fall after VT2 or in the first 40 s, a signal is missing or constant, or the test is shorter than 80 s.
The models
model= |
What it is | Paper |
|---|---|---|
'CNN', the default |
Oxynet's convolutional network, fine-tuned on ramp tests from the Murias lab | Evaluated in Keir et al. (2026) |
'LSTM' |
A recurrent network: one LSTM and one GRU layer | Follows the recurrent approach of Zignoli et al. (2019); not evaluated on its own |
out_df, thresholds = pyoxynet.test_pyoxynet(input_df=df, model='LSTM')
- Both are research models, frozen as they are: they are not retrained.
- The evaluation in Keir et al. covered incremental tests in healthy individuals.
- The domain outputs are what the network gives, not calibrated probabilities, and pyoxynet reports no confidence score.
Where each file came from is recorded in
models/README.md.
The models offered before 1.0.0 (murias_lab, AIS, NSWIS, TCN, LSTMGRUModel) were removed.
Asking for one raises an error that names the available ones, and the earlier releases remain on
PyPI. In 0.1.12, 'CNN' loaded a different network (regressor), so 1.0 gives different
thresholds than 0.1.12 on the same file.
Synthetic and example tests
generator = pyoxynet.load_generator()
df, info = pyoxynet.generate_CPET(generator) # a synthetic ramp test
out_df, thresholds = pyoxynet.test_pyoxynet(input_df=df)
df, info = pyoxynet.draw_real_test() # one of 138 anonymised example tests
info['VT1']andinfo['VT2']are the thresholds the test was generated or labelled with, in seconds.generate_CPET(generator, fitness_group=0)to3sets the fitness level, from very low to high.
The Oxynet API
pyoxynet is the open research package. Oxynet itself is a hosted service at app.oxynet.net, with its own, separately trained models. It reads metabolic cart exports as they come off the cart (COSMED and Cortex among them), checks the signals, and returns ventilatory thresholds, substrate use and signal-quality checks as versioned JSON. API keys are free: app.oxynet.net/signup.
- REST API: developer docs and the OpenAPI schema
- AI assistants: the remote MCP server at
https://app.oxynet.net/oxynet-mcp - AI agents: start at app.oxynet.net/llms.txt, and upload the vendor file unchanged
Questions and citing
Questions and ideas go to GitHub Discussions, bugs to issues.
If you use the CNN, cite:
Keir DA, Zignoli A, Iannetta D, Mattioni Maturana F, Murias JM. AI-Driven Analysis of Cardiopulmonary Exercise Tests to Identify Gas Exchange and Ventilatory Thresholds. Sports Medicine. 2026;56(7):1833-1843. doi:10.1007/s40279-026-02403-w
Background:
- Zignoli A, et al. Expert-level classification of ventilatory thresholds from cardiopulmonary exercising test data with recurrent neural networks. European Journal of Sport Science. 2019;19(9):1221-1229. doi:10.1080/17461391.2019.1587523
- Zignoli A, et al. Oxynet: A collective intelligence that detects ventilatory thresholds in cardiopulmonary exercise tests. European Journal of Sport Science. 2022;22(3):425-435. doi:10.1080/17461391.2020.1866081
- Zignoli A. Machine Learning Models for the Automatic Detection of Exercise Thresholds in Cardiopulmonary Exercising Tests: From Regression to Generation to Explanation. Sensors. 2023;23(2):826. doi:10.3390/s23020826
License and disclaimer
MIT. Research software, not a medical device: it does not diagnose, and its results are no substitute for a clinician's judgement.
Metadata
Release files for pyoxynet 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pyoxynet-1.0.2.tar.gz | 8.2 MB | With provenance | Details for pyoxynet-1.0.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyoxynet-1.0.2-py3-none-any.whl | Python 3 | none | any | Details for pyoxynet-1.0.2-py3-none-any.whl |
Total release size: 16.5 MB
Release files / pyoxynet-1.0.2.tar.gz
| Download URL | pyoxynet-1.0.2.tar.gz |
|---|---|
| Size | 8.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b7bf935c712abf19776600a6661e594e8494e0639fe2bb2720740cfadb05357
|
|
BLAKE2b-256 checksum How to use checksums |
7ec1fdfee9f6cc4f67e3a1477832cecef8ce0fb1e4d50465fa03582fc872b108
|
| 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 29, 2026.
Transparency logRelease files / pyoxynet-1.0.2-py3-none-any.whl
| Download URL | pyoxynet-1.0.2-py3-none-any.whl |
|---|---|
| Size | 8.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3c3f2e5987fc0510d3b1c8593f43ea7e24601617ede92b0beb262873a3caffef
|
|
BLAKE2b-256 checksum How to use checksums |
65c456753dee72cda2c735132ba515dc0f7726a7ac8d211d9d068babe147ed92
|
| 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 29, 2026.
Transparency logSecurity for pyoxynet 1.0.2
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.
Attestation for pyoxynet-1.0.2.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 29, 2026.
Transparency logA 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.