rftools
Python client for rftools.io — 241 RF & electronics calculators, plus 13 async simulation job types (FDTD, antenna NEC-2, filter Monte Carlo, and more), accessible from Python and the command line.
Installation
pip install rftools-io
Quick Start
Get a free API key at rftools.io/pricing (5 calls/month free).
export RFTOOLS_API_KEY=rfc_your_key_here
import rftools
result = rftools.calculate("vswr-return-loss", {"vswr": 2.5})
print(result["returnLoss"]) # 9.54 dB
print(result.values) # {"returnLoss": 9.54, "reflectionCoeff": 0.333, ...}
Authenticated Usage (API tier)
Get an API key at rftools.io/pricing ($19/mo, 10,000 calls/month).
import rftools
client = rftools.Client(api_key="rfc_live_xxx")
# or set environment variable: export RFTOOLS_API_KEY=rfc_live_xxx
result = client.calculate("free-space-path-loss", {"frequency": 2400, "distance": 100})
print(result["pathLoss"]) # dB
Batch Calculations
Run up to 50 calculations in a single HTTP request (API tier only):
results = client.batch([
("vswr-return-loss", {"vswr": 1.5}),
("vswr-return-loss", {"vswr": 2.0}),
("free-space-path-loss", {"frequency": 2400, "distance": 50}),
])
for r in results:
if r.ok:
print(r.values)
else:
print(f"Error: {r.error}")
Typed Category Stubs
IDE-friendly typed functions with parameter defaults matching the web UI:
from rftools.calculators import rf, pcb, antenna, power
# RF
result = rf.vswr_return_loss(vswr=2.5)
result = rf.free_space_path_loss(frequency=2400.0, distance=100.0)
# Antenna
result = antenna.dipole_antenna(frequency=433.0)
result = antenna.parabolic_dish_antenna(frequency=10000.0, diameter=0.6)
# PCB
result = pcb.trace_width_current(current=2.0, tempRise=10.0, thickness=1.0)
# Power
result = power.voltage_divider(vin=12.0, r1=10000.0, r2=10000.0)
All 13 categories available: rf, pcb, power, signal, antenna, general, motor, protocol, emc, thermal, sensor, unit_conversion, audio.
CLI
# Run a calculation
rftools calc vswr-return-loss --vswr 2.5
# With API key
RFTOOLS_API_KEY=rfc_xxx rftools calc free-space-path-loss --frequency 2400 --distance 100
# JSON output (pipe to jq)
rftools calc vswr-return-loss --vswr 2.5 --json | jq '.values.returnLoss'
# Submit an async simulation job, wait for it, print the result summary
rftools sim eye_diagram --param dataRate=10e9 --file trace.s2p
# Submit and return immediately (poll later with the printed job id)
rftools sim fdtd_sparam --param solveMode=express --no-wait
# List all calculators
rftools list
# Filter by category
rftools list --category rf
# Show calculator inputs/outputs
rftools info free-space-path-loss
# Library version
rftools version
Error Handling
Errors are classified by HTTP status code (and, for a finished job, by the service's
errorKind) — never by matching text in a message.
from rftools.exceptions import (
AuthError, QuotaError, RateLimitError, ValidationError, NotFound, JobFailed,
)
try:
result = client.calculate("vswr-return-loss", {"vswr": 2.5})
except QuotaError as e:
print(f"Quota exceeded. Retry after: {e.retry_after}s")
except RateLimitError as e:
print(f"Rate limited. Retry after: {e.retry_after}s")
except AuthError:
print("Invalid API key")
except NotFound:
print("Unknown calculator slug")
except ValidationError as e:
print(f"Bad inputs: {e.failures}")
| Exception | When |
|---|---|
AuthError |
Invalid or missing API key (HTTP 401) — also a spent quota, until the API ships a dedicated 402 for it, and an upload attempted with no key at all, which is raised locally |
QuotaError |
Monthly allowance exhausted (HTTP 402) |
RateLimitError |
Too many requests too fast (HTTP 429) |
ValidationError |
Bad inputs, locally or on the service (HTTP 400/422); .failures is the detail list |
NotFound |
Unknown calculator slug or job id (HTTP 404) |
JobFailed |
A job reached a terminal failed state; .kind is the service's errorKind |
APIError |
Unexpected/unclassified HTTP error, or a network failure |
RftoolsError is the base class for all of the above. Pre-0.2 names (RFToolsError,
NotFoundError) still work as aliases.
Simulation jobs
Async simulation job types — FDTD transmission-line, antenna NEC-2, filter Monte Carlo,
eye diagram, and 9 more — run through the same Client. Parameters and input files are
validated locally against the job type's contract before anything is uploaded or sent.
import rftools
client = rftools.Client(api_key="rfc_live_xxx")
# Submit and wait for it to finish, then fetch a summary of the result
job = client.submit_job(
"eye_diagram",
{"dataRate": 10e9, "prbs": "prbs15"},
files=["trace.s2p"], # paths, or (filename, bytes) tuples
wait=True,
on_progress=lambda j: print(j.status, j.progress, j.stage),
)
print(job.result()) # summary: headline values, warnings, provenance
print(job.result(full=True)) # the whole result payload
# Or submit now, poll later
job = client.submit_job("fdtd_sparam", {"solveMode": "express"})
print(job.id, job.status)
...
job = client.get_job(job.id)
job = job.wait(timeout=60) # returns even if not finished by the deadline
A job that ends in failed raises JobFailed from wait() (or result()), carrying
.kind (one of the service's errorKind values) and the error message.
wait() polls the way the web app does: the first check happens immediately (no fixed
initial delay), then every 2s for the first 30s, every 5s until 5 minutes, and every 15s
after that, until the job reaches completed or failed.
Uploads need a key
Uploading a file needs an API key; set RFTOOLS_API_KEY. The service refuses an
anonymous upload, so upload() and submit_job(files=...) raise AuthError with that
sentence locally — before the file is read and before any request is made. A job type
that takes no file still runs without a key, on the free lane, as before.
The uploaded object is recorded against the key's account, and only that account may submit it: a key obtained from a log or a shared link is refused as though it did not exist.
Uploaded files are capped at 10 MB (the API's limit) — upload()/submit_job() raise
ValidationError locally if a file is over that, before any request is made.
Async Support
import asyncio
import rftools
async def main():
async with rftools.AsyncClient(api_key="rfc_live_xxx") as client:
result = await client.calculate("vswr-return-loss", {"vswr": 2.5})
print(result["returnLoss"])
asyncio.run(main())
Ideal for running many calculations concurrently in FastAPI or async scripts.
Browse the Catalog
# List all calculators
calcs = rftools.list_calculators()
print(f"{len(calcs)} calculators available")
# Filter by category
rf_calcs = rftools.list_calculators(category="rf")
for c in rf_calcs:
print(f"{c.slug}: {c.title}")
# Get a single calculator's metadata
info = rftools.get_calculator("vswr-return-loss")
print(info.inputs) # tuple of InputField
print(info.outputs) # tuple of OutputField
All Calculator Categories
The typed stub catalog (rftools/calculators/, rftools.list_calculators()) is
generated from a snapshot of the registry and is due for a refresh to the current
241; run python scripts/generate_stubs.py --frontend-dir /path/to/rfhub/frontend
to regenerate it. The counts below describe that snapshot.
| Category | Count | Example |
|---|---|---|
rf |
26 | vswr-return-loss, free-space-path-loss, rf-link-budget |
pcb |
13 | trace-width-current, via-calculator, microstrip-impedance |
power |
20 | voltage-divider, led-resistor, battery-life |
signal |
13 | filter-designer, op-amp-gain, pwm-duty-cycle |
antenna |
8 | dipole-antenna, eirp-calculator, parabolic-dish-antenna |
general |
21 | lc-resonance, ohms-law, rc-time-constant |
motor |
18 | brushless-dc-motor, stepper-motor, servo-motor |
protocol |
11 | uart-baud-rate, i2c-pullup, can-bus-bit-timing |
emc |
16 | emi-filter-lc, shielding-effectiveness, ground-loop |
thermal |
6 | thermal-resistance, heat-sink, junction-temperature |
sensor |
17 | thermistor-ntc, strain-gauge, hall-effect |
unit-conversion |
17 | dbm-watts, frequency-wavelength, temperature |
audio |
17 | speaker-crossover, amplifier-gain, room-acoustics |
Contributing
Regenerate stubs after calculator changes:
python scripts/generate_stubs.py --frontend-dir /path/to/rfhub/frontend
Then bump the version in pyproject.toml and publish a new release.
License
MIT — see LICENSE.
Release files for rftools-io 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rftools_io-0.2.0.tar.gz | 191.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rftools_io-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 388.2 kB
Release files / rftools_io-0.2.0.tar.gz
| Download URL | rftools_io-0.2.0.tar.gz |
|---|---|
| Size | 191.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d1cf945b5e17f3e2e5fa85397be59c939e77cc70b3f1732b52bead02be6e6228
|
|
BLAKE2b-256 checksum How to use checksums |
01bb6869cd952c8dca14dd88295251bc2835af53fcb6fef033b97a2ffbc22b41
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 23, 2026.
Transparency logRelease files / rftools_io-0.2.0-py3-none-any.whl
| Download URL | rftools_io-0.2.0-py3-none-any.whl |
|---|---|
| Size | 196.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b41643dea543990d24059e395d61e30e9669a91474c020b0c8e01abcb41d254a
|
|
BLAKE2b-256 checksum How to use checksums |
8d74840223cb0117b0b1bfa6efb18de28997541b0870af2313500490025d25c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 23, 2026.
Transparency log