Automate RF Calculations in Python with rftools
The rftools Python package gives you programmatic access to 203 RF and electronics calculators from rftools.io — with a typed API, CLI, batch mode, and async support.
Contents
Why Automate RF Calculations?
Running a single VSWR calculation by hand is fine. But when you're doing a parameter sweep across 50 distances, comparing link budgets for 12 antenna configurations, or writing a Jupyter notebook for a design review, clicking through a web UI isn't the answer.
The rftools Python package gives you the full rftools.io calculator engine in your Python environment — no web scraping, no copy-pasting — just clean, typed function calls.
Installation
pip install rftools-io
A free API key is required — get one at rftools.io/pricing (5 calls/month free). For automated workflows, the API tier gives you 10,000 calls/month.
Your First Calculation
import rftools
result = rftools.calculate('vswr-return-loss', {'vswr': 2.5}) print(f'Return Loss: {result["returnLoss"]:.2f} dB') # 9.54 dB print(f'Reflection Coeff: {result["reflectionCoeff"]:.3f}') # 0.333
rftools.calculate() returns a CalculatorResult — dict-like, so you can access outputs by key.
Typed Stubs for IDE Autocomplete
For better discoverability and IDE completion, use the typed category modules:
from rftools.calculators import rf, antenna, pcb
# Parameter names and defaults match the rftools.io web UI fspl = rf.free_space_path_loss(frequency=2400.0, distance=100.0) print(f'FSPL: {fspl["pathLoss"]:.1f} dB') # 80.0 dB
dipole = antenna.dipole_antenna(frequency=433.0) print(f'Dipole length: {dipole["length"]:.0f} mm')
All 13 categories are available: rf, pcb, power, signal, antenna, general, motor, protocol, emc, thermal, sensor, unit_conversion, audio.
Batch Mode (API Tier)
The batch API runs up to 50 calculations in a single HTTP request — ideal for sweeps:
import rftools
client = rftools.Client(api_key='rfc_live_xxx') # or: export RFTOOLS_API_KEY=rfc_live_xxx
distances = [10, 50, 100, 500, 1000] results = client.batch([ ('free-space-path-loss', {'frequency': 2400, 'distance': d}) for d in distances ])
for d, r in zip(distances, results): if r.ok: print(f'{d:>6}m → {r.values["pathLoss"]:.1f} dB')
Output:
10m → 60.0 dB 50m → 74.0 dB 100m → 80.0 dB 500m → 94.0 dB 1000m → 100.0 dB
Async Support
For FastAPI services or async Jupyter kernels, use AsyncClient:
import asyncio
import rftools
async def main(): async with rftools.AsyncClient(api_key='rfc_live_xxx') as client: result = await client.calculate('rf-link-budget', { 'txPower': 20, 'txGain': 6, 'rxGain': 3, 'frequency': 2400, 'distance': 500, }) print(f'Received power: {result["rxPower"]:.1f} dBm')
asyncio.run(main())
CLI
The rftools command runs calculations from the terminal:
# Single calculation
rftools calc vswr-return-loss --vswr 2.5
# JSON output — pipe to jq rftools calc vswr-return-loss --vswr 2.5 --json | jq '.values.returnLoss'
# List available calculators rftools list --category rf
# Show a calculator's inputs and outputs rftools info free-space-path-loss
The CLI is useful for quick checks in terminal workflows or shell scripts.
Error Handling
All errors raise typed exceptions:
from rftools.exceptions import AuthError, RateLimitError, ValidationError
try: result = client.calculate('vswr-return-loss', {'vswr': 2.5}) except RateLimitError as e: print(f'Quota exceeded. Retry after {e.retry_after}s') except AuthError: print('Invalid API key') except ValidationError as e: print(f'Bad inputs: {e.detail}')
Browsing the Calculator Catalog
# All 203 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}')
# Inspect a specific calculator's inputs and outputs info = rftools.get_calculator('noise-figure-cascade') for field in info.inputs: print(f' in: {field.id} ({field.unit})') for field in info.outputs: print(f' out: {field.id} ({field.unit})')
A Practical Example: Link Budget Sweep
Here's how to build a receive-power-vs-distance chart in a Jupyter notebook:
import numpy as np
import matplotlib.pyplot as plt
from rftools.calculators import rf
distances = np.logspace(1, 4, 40) # 10m to 10km rx_powers = []
for d in distances: r = rf.rf_link_budget( txPower=30, # dBm txGain=6, # dBi rxGain=6, # dBi frequency=915, # MHz distance=float(d), ) rx_powers.append(r['rxPower'])
plt.semilogx(distances, rx_powers) plt.axhline(-100, color='r', linestyle='--', label='Sensitivity (-100 dBm)') plt.xlabel('Distance (m)') plt.ylabel('Received Power (dBm)') plt.title('915 MHz Link Budget') plt.legend() plt.grid(True) plt.show()
Getting Started
Install with pip install rftools-io. Source and issues: github.com/rftools/rftools-py. API keys and pricing at rftools.io/pricing.
Related Articles
From Frequency to Physical Dimensions: How Wavelength Shapes Every RF Design Decision
Learn how to convert frequency to wavelength in free space and PCB substrates. Worked examples for WiFi, radar, and antenna design using our calculator.
Mar 15, 2026
Antenna DesignDesigning Small Loop Antennas: Radiation Resistance, Gain, and Bandwidth Demystified
Learn how to design small loop antennas with real examples. Calculate radiation resistance, gain, loss resistance, and bandwidth for HF loops.
Mar 14, 2026
Power ElectronicsTaming Capacitor Inrush: How to Size an NTC Thermistor for Your Power Supply
Learn how to calculate NTC thermistor cold resistance, energy absorption, and time constant to limit inrush current in capacitive power supplies.
Mar 13, 2026