This repository is for building a Python interface to SDRplay RSPdx-R2 hardware. The actual implementation will be generated with opencode/Qwen3, using the SDRplay API already installed on the target machine.
- RSPdx-R2 product page: https://www.sdrplay.com/rspdxr2/
- SDRplay API page: https://www.sdrplay.com/api/
- SDRplay API Specification v3.15: https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.15.pdf
- Target hardware: SDRplay RSPdx-R2.
- Required SDRplay API version: 3.15 or later.
- The SDRplay API service/daemon and shared library are already installed.
- The Python code should call the native SDRplay API through
ctypes. - Initial implementation targets one RSPdx-R2 device and single-tuner operation.
RSPdx-R2 hardware
↓
SDRplay API 3.15
↓
rspdx_r2 ctypes wrapper
↓
capture_iq()
iter_iq_chunks()
↓
capture.json / capture.npy / capture.raw / SigMF
↓
AI-CW-Decoder
- device discovery
- configure()
- capture_iq()
- realtime iter_iq_chunks()
- npy export
- raw export
- metadata export
- SigMF metadata export
- inspect_capture.py
- analyze_capture.py
Prerequisite: install SDRplay API separately.
macOS downloads:
https://www.sdrplay.com/downloads/
Install this Python wrapper in editable mode:
pip install -e .This project does NOT redistribute:
- SDRplay API binaries
- SDRplay API headers
- SDK packages
- installers
This project uses SDRplay API as an external runtime dependency.
- This is a Python
ctypeswrapper project. - SDRplay API runtime is required.
- SDRplay hardware is required.
- SDRplay API must be installed separately.
Official SDRplay website:
Downloads:
https://www.sdrplay.com/downloads/
API Documentation:
Dependency relationship:
RSPdx-R2 hardware
↓
SDRplay API runtime
↓
rspdx_r2 Python wrapper
↓
capture / realtime streaming / export
This repository contains original Python code only.
The following are NOT redistributed:
- SDRplay API binaries
- SDRplay API headers
- SDRplay SDK packages
- SDRplay installers
- SDRplay trademarks
Users must obtain SDRplay API directly from SDRplay Ltd.
macOS example:
-
Install SDRplay API from:
-
Verify installation:
find /Library/SDRplayAPI \ -iname "*license*" \ -o -iname "*readme*"
-
Verify API runtime:
python examples/api_version.py
-
Verify hardware detection:
python examples/list_devices.py
The first implementation should provide a small, safe, testable Python package that can:
- Load the SDRplay native API library.
- Open and close the API.
- Check the installed API version.
- Enumerate attached SDRplay devices.
- Select an RSPdx-R2 device.
- Read device parameters.
- Configure basic tuner settings.
- Start a short IQ stream capture.
- Stop streaming and release all API resources reliably.
The first generated version should include these example scripts:
examples/api_version.py- Prints the loaded SDRplay API version.
examples/list_devices.py- Lists visible SDRplay devices and identifies RSPdx-R2 if present.
examples/capture_iq.py- Captures a short IQ sample file with explicit frequency, sample rate, and duration.
Example target usage:
python examples/api_version.py
python examples/list_devices.py
python examples/capture_iq.py --center-hz 100000000 --sample-rate 2000000 --duration-sec 1 --out capture.npy- Do not perform OS-level configuration changes.
- Do not install, update, remove, start, stop, or restart system services.
- Do not use
sudoin generated code or examples. - Bias-T must default to disabled.
- HDR mode must default to disabled unless explicitly requested.
- Device resources must be released on normal exit, exceptions, and Ctrl-C.
- Streaming callbacks must avoid heavy work and should only move samples into a queue or ring buffer.
rspdx_r2/
__init__.py
loader.py
errors.py
constants.py
structs.py
config.py
device.py
stream.py
examples/
api_version.py
list_devices.py
capture_iq.py
tests/
test_config_validation.py
test_error_mapping.py
See SPEC.md for the detailed implementation specification.
examples/capture_iq.py exports RSPdx-R2 IQ captures as a small file set:
capture.npy: NumPycomplex64IQ samples.capture.raw: raw interleaved signed 16-bit IQ samples.capture.json: metadata and file references for the capture.
capture.json is the integration entry point. AI-CW-Decoder should receive the
metadata JSON path, validate it, and then load the referenced IQ data.
AI-CW-Decoder should prefer npy_path when it is present and the metadata
declares complex64_npy in export_format. Only read raw_path when npy_path
is missing or not exported.
Required keys:
schema_version: must be"rspdx-r2-capture-v1".source: must be"rspdx-r2".export_format: list of exported data formats, for example["complex64_npy", "interleaved_int16_iq"].center_hz: RF center frequency in Hz.sample_rate_hz: sample rate in Hz.duration_sec: requested capture duration in seconds.antenna: selected antenna, normally"A","B", or"C".sample_count: number of complex IQ samples.dtype: expected NumPy dtype for the preferred.npyexport.npy_path: path to the.npyexport, ornull.raw_path: path to the.rawexport, ornull.raw_format: raw export format, currently"interleaved_int16_iq".iq_order: raw IQ order, currently"I,Q".created_by: producer identifier.
Relative npy_path and raw_path values are resolved relative to the parent
directory of capture.json.
complex64_npy:
- Read with
np.load(path). dtypemust becomplex64.shapemust be(sample_count,).
interleaved_int16_iq:
- Read with
np.fromfile(path, dtype=np.int16). - Layout is
I0,Q0,I1,Q1,.... - Element count must be
sample_count * 2. - Restore to
complex64with:real = raw[0::2]imag = raw[1::2]
metadata = json.load(open(metadata_json))
base_dir = Path(metadata_json).resolve().parent
npy_path = base_dir / metadata["npy_path"] if metadata["npy_path"] else None
raw_path = base_dir / metadata["raw_path"] if metadata["raw_path"] else None
if "complex64_npy" in metadata["export_format"] and npy_path:
iq = np.load(npy_path).astype(np.complex64)
else:
raw = np.fromfile(raw_path, dtype=np.int16)
iq = raw[0::2].astype(np.float32) + 1j * raw[1::2].astype(np.float32)
iq = iq.astype(np.complex64)AI-CW-Decoder should read capture.json as the canonical entry point.
AI-CW-Decoder users must install SDRplay API separately. This repository does
not vendor the SDRplay SDK. capture.json remains the canonical integration
point for saved IQ exports.
Recommended loading order:
- Load
capture.json. - If
"complex64_npy"is inexport_format, usenpy_path. - Otherwise, reconstruct IQ from
raw_path. - Validate:
schema_versionsourcesample_countraw_formatiq_order
- Feed the resulting IQ
ndarrayinto the decoder.
AI-CW-Decoder realtime integration can consume iter_iq_chunks() instead of
reading saved capture files.
with RspDxR2Device() as dev:
dev.open()
dev.select_rspdx_r2()
dev.configure(config)
for chunk in dev.iter_iq_chunks(
duration_sec=3,
chunk_samples=8192,
):
process(chunk)- Repository code is licensed under the MIT License.
- The SDRplay SDK/API is a separate proprietary dependency.
- Users must install SDRplay API independently from SDRplay Ltd.
- This repository contains original Python wrapper code only.
- SDRplay API binaries, libraries, headers, installers, SDK packages, and trademarks belong to SDRplay Ltd and are not redistributed here.
Before publishing or cutting a release, verify generated captures are ignored:
git check-ignore -v \
capture.raw \
capture.sigmf-meta \
capture.jsonVerify proprietary SDRplay artifacts are not tracked:
git ls-files | grep -Ei \
"sdrplay|\.dylib$|\.so$|sdk|installer|header"Expected result: no SDRplay API binary, header, SDK archive, or installer file is tracked in this repository.