Skip to main content

rf-bench-drivers-nanovna

Python driver for the NanoVNA family of low-cost vector network analyzers — the original edy555 NanoVNA, hugen79 NanoVNA-H / NanoVNA-H4, DiSlord NanoVNA-H4 builds, and the Deepelec NanoVNA-F (verified 2026-06-30 against an F-series HW2.3/HW3.1 running firmware 0.2.1).

Speaks the ASCII shell protocol over the on-board USB CDC serial port (no NanoVNA-Saver / nanovna-python dependency). Returns numpy arrays.

Status

🧪 First release. Verified against the user's NanoVNA-F: identify, setup_sweep, get_frequencies, get_s11, get_s21, get_trace_db, get_trace_phase, set_parameter, set_marker, is_correction_on, average_s_data, single_sweep, pause, resume, get_trace_db_at, refusal of S12/S22 and set_power(dbm). Calibration flow (cal_open/short/load/isoln/thru/done/save) is wired but has not been exercised end-to-end with the user's cal kit.

Not yet supported:

  • NanoVNA-V2 / S-A-A-2 (binary protocol — a different driver class).
  • LiteVNA / NanoVNA-F V2 (also binary protocol).

Supported hardware

Variant Protocol Tested?
NanoVNA (edy555 original) ASCII shell over CDC ✅ same protocol family
NanoVNA-H / H4 (hugen79) ASCII shell over CDC ✅ same protocol family
NanoVNA-H4 (DiSlord) ASCII shell over CDC (superset) ✅ extras via .raw()
NanoVNA-F (Deepelec) ASCII shell over CDC ✅ tested 2026-06-30
NanoVNA-V2 / S-A-A-2 binary protocol ❌ not supported
LiteVNA binary protocol ❌ not supported

Install

pip install rf-bench-drivers-nanovna

or development:

cd drivers/nanovna
pip install -e . --break-system-packages

Requires pyserial>=3.5 and numpy>=1.20.

Quick start

from rf_bench.nanovna import NanoVNA
import numpy as np

with NanoVNA("/dev/ttyACM1") as vna:        # autodetect: NanoVNA()
    print(vna.identify())
    vna.setup_sweep(start_hz=1e6, stop_hz=900e6, points=101)
    freqs, s11, s21 = vna.get_s_data_full() # all three at once
    print(f"S11 dB: {20*np.log10(np.abs(s11)+1e-30).min():.1f}")

Swappable API with HP 8712B

This driver implements the same core method names as rf_bench.hp.HP8712B, so projects can switch between them by changing only the construction call:

def run(vna):
    vna.setup_sweep(1e6, 900e6, points=101)
    vna.set_parameter("S11")
    vna.single_sweep()
    freqs = vna.get_frequencies()
    s_data = vna.get_s_data()
    db = vna.get_trace_db()
    phase = vna.get_trace_phase()
    return freqs, s_data, db, phase

# Works with either driver:
from rf_bench.nanovna import NanoVNA
from rf_bench.hp import HP8712B
run(NanoVNA())
run(HP8712B("10.1.1.70"))

Methods available on both drivers:

Method NanoVNA HP 8712B
identify() -> str ✅ ✅
setup_sweep(start, stop, points) ✅ ✅
set_parameter("S11" | "S21" | "S12" | "S22") ✅ (S11/S21 only) ✅
get_parameter() -> str ✅ ✅
set_format("MLOG" | "PHAS" | ...) ✅ ✅
single_sweep() -> bool ✅ ✅
pause() / resume() / hold() / continuous() ✅ ✅
get_frequencies() -> ndarray ✅ ✅
get_s_data() -> ndarray (complex) ✅ (selected param) ✅ (selected param)
get_trace_db() -> ndarray ✅ ✅
get_trace_phase() -> ndarray ✅ ✅
get_trace_db_at(freq_hz) -> float ✅ ✅
get_s11() -> ndarray ✅ ✅
get_s21() -> ndarray ✅ ✅
set_marker(freq_hz, marker=1) ✅ ✅
get_marker_value(marker=1) -> float ✅ ✅
marker_off(marker=1) ✅ ✅
correction_on() / correction_off() / cal_on() / cal_off() ✅ ✅
is_correction_on() -> bool ✅ ✅
average_s_data(n) -> ndarray ✅ ✅
close() / context manager ✅ ✅

Methods NanoVNA-only (HP raises AttributeError):

  • get_s_data_full() -> (freqs, s11, s21) — exploits the NanoVNA's simultaneous S11+S21 measurement (HP must re-sweep per parameter)
  • cal_reset/open/short/load/isoln/thru/done — SOLT walkthrough
  • save_cal(slot) / recall_cal(slot) — flash slots
  • iter_segments(start, stop, seg_points) — span > 401 points across segments
  • set_marker_index(marker, point_index) — direct index addressing
  • raw_power_index(0..3) — coarse hardware power index
  • raw(cmd) -> str — escape hatch to the shell

Methods HP-only (NanoVNA raises NotImplementedError):

  • set_power(dbm) — NanoVNA exposes only a coarse index (raw_power_index)
  • set_averaging(count) — NanoVNA firmware has no host-side averaging control; use average_s_data(n) for software averaging

S-parameter scope: NanoVNA hardware is forward-only (1.5-port VNA). set_parameter("S12") / set_parameter("S22") raise NotImplementedError. To measure S22 / S12 on a DUT, reverse it physically and re-measure as S11 / S21 from the new orientation.

Calibration

SOLT walkthrough for the standard 12-term error model:

with NanoVNA() as vna:
    vna.setup_sweep(1e6, 900e6, points=101)
    vna.cal_reset()
    input("Attach OPEN to port 0,  press Enter…"); vna.cal_open()
    input("Attach SHORT to port 0, press Enter…"); vna.cal_short()
    input("Attach LOAD  to port 0, press Enter…"); vna.cal_load()
    input("Attach LOAD  to port 1, press Enter…"); vna.cal_isoln()
    input("Connect THRU port 0→1,   press Enter…"); vna.cal_thru()
    vna.cal_done()
    vna.save_cal(0)            # save to flash slot 0

To recall later:

with NanoVNA() as vna:
    vna.setup_sweep(1e6, 900e6, points=101)
    vna.recall_cal(0)

Calibration applies only over the swept range it was measured at. Change the sweep, recalibrate.

Building & publishing

cd drivers/nanovna
python -m build
twine upload dist/* --skip-existing

License

GPL-3.0-or-later

Metadata

Release files for rf-bench-drivers-nanovna 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 rf-bench-drivers-nanovna 0.1.0
File Size Uploaded Provenance Actions
rf_bench_drivers_nanovna-0.1.0.tar.gz 29.3 kB Without provenance Details for rf_bench_drivers_nanovna-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for rf-bench-drivers-nanovna 0.1.0
File Interpreter ABI Platform Actions
rf_bench_drivers_nanovna-0.1.0-py3-none-any.whl Python 3 none any Details for rf_bench_drivers_nanovna-0.1.0-py3-none-any.whl

Total release size: 57.1 kB

Release files / rf_bench_drivers_nanovna-0.1.0.tar.gz

Download URL rf_bench_drivers_nanovna-0.1.0.tar.gz
Size 29.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5cb7cd920d25c0948b6ed988341a1d9dfc6e2d0ca1bccc5ab60c42c9fcbccf48
BLAKE2b-256 checksum
How to use checksums
fdc6441efd0f0a9a9d30dfb947d56d33184fa6952ef3f32b155580c30466a5ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

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

Download URL rf_bench_drivers_nanovna-0.1.0-py3-none-any.whl
Size 27.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
71e42f06a4a963897e70f3b0ac519a6a8e328b8c15313ea4455b3f71261b29c6
BLAKE2b-256 checksum
How to use checksums
dfc22a9bf7ace0a83d17b7f97f1ab99cd8ed7b8d7cbbdf6de91b08fdbf65a291
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Security for rf-bench-drivers-nanovna 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.

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

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