Getting Started
This is a practical reference for the ria CLI from ria-toolkit-oss.
Scope of this guide:
Installation and SDR driver prerequisites — how to install RIA Toolkit OSS and configure the system drivers your hardware requires
End-to-end CLI workflow — a step-by-step walkthrough from hardware discovery through capture, annotation, and processing
Full command reference — options, flags, and examples for every
riacommandPython scripting preview — using the toolkit API directly without the CLI
Official resources:
1) Installation and Setup
Before using the ria CLI, follow the Installation guide to
install RIA Toolkit OSS and any SDR drivers required for your hardware.
1.1 SDR driver prerequisites
Toolkit package install does not install all system SDR drivers. Install vendor/runtime dependencies for the hardware you use.
Examples (depends on device and OS):
Device |
Driver Package |
|---|---|
USRP |
UHD drivers |
Pluto |
libiio / IIO utilities |
BladeRF |
libbladeRF |
HackRF |
libhackrf |
RTL-SDR |
librtlsdr |
See repo docs under docs/source/sdr_guides/* and your OS package instructions.
2) CLI Structure
Top-level CLI follows this model:
ria [GLOBAL_OPTS] <command> [ARGS] [OPTIONS]
Global:
-v, --verbose(defined on root click group)
Top-level commands:
Command |
Purpose |
|---|---|
Probe SDR drivers and enumerate attached hardware |
|
Create and manage user metadata defaults |
|
Record IQ samples from a connected SDR |
|
Generate visualizations from IQ files |
|
Label signal regions manually or with auto-detection (group) |
|
Convert between IQ file formats |
|
Split, trim, or extract recordings |
|
Merge multiple recordings by concatenation or addition |
|
Generate synthetic IQ signals (group; |
|
Apply augmentations or impairments to recordings (group) |
|
Transmit IQ through a TX-capable SDR |
3) Quick End-to-End Workflow
3.1 Discover radios
Run this first to verify drivers and detect connected hardware.
ria discover -v
See discover for JSON output and troubleshooting options.
3.2 Initialize local metadata defaults
Set reusable metadata once so captured files include consistent provenance fields.
ria init
See init for non-interactive and config path options.
3.3 Capture IQ
Record baseband IQ from a connected SDR.
ria capture -d pluto -f 2.44G -s 2e6 -n 500000 -o capture.sigmf-data
See capture for all device, format, and metadata options.
3.4 Visualize and inspect
Render a quick diagnostic plot to validate signal presence and quality.
ria view capture.sigmf-data --type simple
See view for full multi-panel plots and display options.
3.5 Auto-annotate and inspect annotations
Detect signal regions automatically, then verify the results.
ria annotate energy capture.sigmf-data --label signal
ria annotate list capture.sigmf-data
See annotate for threshold tuning and other detection methods.
3.6 Convert and split
Convert to a different format and split into fixed-size chunks.
ria convert capture.sigmf-data capture.npy
ria split capture.sigmf-data --split-every 100000 --output-dir chunks
3.7 Apply transforms
Augment or impair a recording to produce controlled variants.
ria transform impair add_awgn_to_signal capture.npy --params snr=10
See transform for available augmentations and custom transforms.
3.8 Transmit (TX-capable radios only)
Replay a recording through a transmit-capable SDR.
ria transmit -d hackrf -f 2.44G -s 2e6 --input capture.sigmf-data
See transmit for continuous mode and generated waveform options.
4) Command Reference
4.1 discover
Purpose:
Probe available SDR drivers and enumerate attached hardware.
Confirm whether runtime libraries/drivers are installed and discoverable before capture/transmit.
Usage:
ria discover [--verbose] [--json-output]
Options:
-v, --verbose: include per-driver probe details and import/init failures.--json-output: emit JSON (useful for automation and inventory scripts).
Behavior notes:
discoverchecks multiple backends (USB and network paths, depending on driver support).A device not appearing here usually means one of: missing system driver, permission issue, USB/network connectivity issue.
Use
--verbosefirst when troubleshooting; it surfaces driver-level failures that are hidden in default output.
Example output:
Run ria discover -v to see loaded drivers, failure reasons, and attached devices:
$ ria discover -v
✅ Loaded drivers (3):
hackrf
pluto
bladerf
❌ Failed drivers (3):
usrp: ModuleNotFoundError: uhd
rtlsdr: ImportError: pyrtlsdr is required to use the RTLSDR class
thinkrf: ImportError: pyrf is required to use the ThinkRF integration.
Install with: pip install ria-toolkit-oss[thinkrf]
========================================
Attached Devices
========================================
📡 USRP/UHD devices (1):
✅ MyB200 (B200) - Serial: 30C51D5
📱 PlutoSDR devices: None found
🔧 HackRF devices: None found
========================================
Discovery Summary
========================================
Loaded drivers: 3
Failed drivers: 3
Detected devices: 1
With --json-output (useful for scripting and automation):
{
"loaded_drivers": ["hackrf"],
"failed_drivers": ["pluto", "bladerf", "usrp", "rtlsdr", "thinkrf"],
"devices": [
{
"type": "BladeRF",
"Description": "Nuand bladeRF 2.0",
"Backend": "libusb",
"Serial": "8518b488d3e3443da979680f472bbb87",
"USB Bus": "4",
"USB Address": "2"
}
],
"total_devices": 1
}
Note
Driver load failures are normal on systems where only a subset of SDR backends are installed. A failed driver just means that backend’s Python library isn’t present — it does not prevent other drivers from working. Install only the packages for the hardware you use.
4.2 init
Purpose:
Create/manage user config file (defaults to
~/.ria/config.yaml, or$XDG_CONFIG_HOME/ria/config.yaml).
Usage:
ria init [options]
Options:
--author,--organization,--project,--location,--testbed,--license,--hw,--dataset: stored once and reused for later recordings so files have consistent provenance.--show: read-only inspect of the current resolved config.--reset: remove config and start clean.--config-path: use a non-default config location (useful for isolated environments or CI).--interactive/--no-interactive: force prompts on or off regardless of terminal auto-detection.--yes: suppress confirmation prompts for scripted runs.
Example output:
Set metadata fields non-interactively:
$ ria init --author "Jane Doe" --project "rf-campaign-1" --location "Lab-A" --no-interactive
✓ Configuration saved to: /home/user/.ria/config.yaml
Then verify what was saved with --show:
$ ria init --show
Current Configuration (/home/user/.ria/config.yaml):
============================================================
Author: Jane Doe
Project: rf-campaign-1
Location: Lab-A
To update: ria init
To reset: ria init --reset
Note
Config integration is still being finalized. Config values are already consumed by multiple commands (capture, convert, generate metadata, and YAML config loading paths).
4.3 capture
Purpose:
Record IQ samples from a supported SDR and save to
sigmf,npy,wav, orblue.
Usage:
ria capture [options]
Device selection (--device) is optional if only one device is detected. Exactly one of
--num-samples or --duration is required.
Options:
-d, --device {pluto,hackrf,bladerf,usrp,rtlsdr,thinkrf}-i, --ident: serial or IP selector when multiple devices of the same type are present.-c, --config <yaml>: load options from a YAML file; CLI flags override loaded values.-s, --sample-rate-f, --center-frequency(supports values like915e6,2.4G)-g, --gain,-b, --bandwidth-n, --num-samplesor-t, --duration: use sample count for deterministic datasets, or duration for quick time-based acquisition.-o, --output,--output-dir: output path or directory. A timestamped filename is generated if--outputis omitted; defaults torecordings/if--output-diris omitted.--format {npy,sigmf,wav,blue}: inferred from file extension if not set.sigmfis best for annotation workflows.--save-image: writes a quick visual summary alongside the capture file.-m, --metadata KEY=VALUE(repeatable): injects run-specific metadata.-v, --verbose,-q, --quiet
Examples:
ria capture -d hackrf -s 2e6 -f 2.44G -n 1000000 -o rf.sigmf-data
ria capture -d pluto -f 915e6 -t 2 --format npy --output-dir recordings
ria capture -c capture_config.yaml
Example output:
Note
capture requires a connected SDR. The following shows representative output for a
HackRF capture.
$ ria capture -d hackrf -s 2e6 -f 2.44G -n 1000000 -o rf.sigmf-data
Initializing HackRF...
Device: HackRF One
Serial: a74ad5e4e2a14b7d
Center frequency: 2.44 GHz
Sample rate: 2.00 MS/s
Gain: 20 dB
Capturing 1,000,000 samples...
Saved: rf.sigmf-data
rf.sigmf-meta
4.4 view
Purpose:
Generate visualizations from IQ files.
Quickly validate signal quality, occupancy, and annotation coverage without writing custom plotting code.
Usage:
ria view <input> [options]
<input> accepts SigMF, NPY, WAV, and Blue files.
Mode (--type):
simple: fast-look plots for sanity checks and quick iteration.full: multi-panel diagnostic figure (IQ, time, frequency, metadata views).annotations/annotation: render annotation overlays.channels: channelized/segmented visualization.annotate: convenience path used in some annotation workflows.
Output/display options:
--output,--format {png,pdf,svg,jpg}--show: open an interactive window (requires a GUI display environment).--no-save: suppress file output; only meaningful with--show.--overwrite
Style options:
--dpi,--figsize WxH,--title--light: switch to a light theme (useful for reports/slides).
Loading options:
--legacy: force legacy NPY loading path for older datasets.--config
Mode-specific options:
simple: --fast, --compact, --horizontal, --constellation, --labels,
--slice start:end[:step]
full: --plot-length, --no-spectrogram, --no-iq, --no-frequency,
--no-constellation, --no-metadata, --no-logo, --spines
annotations / channels: --channel
Examples:
ria view capture.sigmf-data --type simple
ria view capture.npy --type full --title "Test Capture" --format pdf
ria view capture.npy --show --no-save
ria view old.npy --legacy --type simple
ria view recordings\qam64_35.npy --type simple
ria view recordings\qam64_35.npy --type full
Example output:
$ ria view qam64_35.npy --type simple
Loading recording: qam64_35.npy
Recording Metadata:
----------------------------------------
modulation: qam64
constellation: qam
bits_per_symbol: 6
sps: 6
beta: 0.35
source: signal.block_generator
----------------------------------------
Generating simple visualization...
Saved: qam64_35.png
Output of ria view qam64_35.npy --type simple
Output of ria view qam64_35.npy --type full
4.5 annotate group
Purpose:
Manual annotation management and auto-detection/separation.
Build or refine label metadata directly in recordings for downstream training, QA, and filtering.
Usage:
ria annotate <subcommand> ...
Subcommands:
Subcommand |
Purpose |
|---|---|
|
Inspect all annotations on a recording |
|
Add one annotation with explicit sample-domain bounds |
|
Remove one annotation by index |
|
Remove all annotations from a recording |
|
Auto-detect regions above the estimated noise floor |
|
Auto-detect regime changes using change-point detection |
|
Auto-detect regions using normalized magnitude thresholding |
|
Decompose annotations into narrower spectral components |
SigMF is the preferred format for durable annotation metadata. For non-SigMF input, most
operations write a new output artifact unless --overwrite is set.
--type {standalone,parallel,intersection} controls annotation relation semantics.
Manual subcommands:
ria annotate list
ria annotate list <input> [--verbose]
Prints all annotations for a recording in index order. --verbose includes additional
detail per record.
ria annotate add
ria annotate add <input> --start <int> --count <int> --label <text> [options]
Adds one explicit annotation with sample-domain boundaries.
--start: first sample index of the annotated region.--count: number of samples in the region.--freq-lower,--freq-upper: optional spectral bounds in Hz.--comment,--type,-o/--output,--overwrite,--quiet
ria annotate remove
ria annotate remove <input> <index> [--output ...] [--overwrite] [--quiet]
Removes exactly one annotation by list index. Run annotate list first to confirm the
index.
ria annotate clear
ria annotate clear <input> [--force] [--overwrite] [--quiet]
Removes all annotations from the recording. --force bypasses the confirmation prompt.
Automatic detection subcommands:
ria annotate energy
ria annotate energy <input> [options]
Detects energetic regions above the estimated noise floor and writes them as annotations.
--label--threshold: noise-floor multiplier; higher values reduce false positives but can miss weak signals.--segments: number of segments used to estimate baseline noise.--window-size: smoothing size; larger windows stabilize detections at the cost of sharp transition precision.--min-distance: minimum sample spacing between detections, preventing dense duplicate regions.--freq-method {nbw,obw,full-detected,full-bandwidth}: how frequency bounds are assigned to annotations.--nfft,--obw-power--type,-o/--output,--overwrite,--quiet
ria annotate threshold
ria annotate threshold <input> --threshold <0.0..1.0> [options]
Uses normalized magnitude thresholding to derive annotation spans. Use where a fixed amplitude threshold is sufficient.
--label,--window-size,--type,-o/--output,--overwrite,--quiet
ria annotate cusum
ria annotate cusum <input> [options]
Uses change-point detection (CUSUM-style logic) to find regime changes and annotate contiguous segments.
--label--min-duration(ms): prevents tiny over-segmented labels.--window-size--tolerance: merges nearby boundaries when set above default.--type,-o/--output,--overwrite,--quiet
ria annotate separate
ria annotate separate <input> [options]
Decomposes existing annotations into narrower sub-band annotations by detecting distinct
frequency components within each annotated time window. It does not detect signal regions
from scratch — run energy, threshold, or cusum first to produce the input
annotations, then use separate to refine them spectrally.
Use this when a single broad annotation covers multiple signals at different frequencies and you want separate annotations per component.
--indices "0,1,2": limit operation to specific annotations; omit to process all.--nfft: larger FFT improves frequency resolution but increases compute time.--noise-threshold-db: sets the noise floor in dB; auto-estimated if omitted.--min-component-bw: rejects narrow fragments likely to be noise artifacts.-o/--output,--overwrite,--quiet,--verbose
Examples:
ria annotate list capture.sigmf-data --verbose
ria annotate add capture.sigmf-data --start 10000 --count 5000 --label burst
ria annotate energy capture.sigmf-data --label signal --threshold 1.3
ria annotate threshold capture.sigmf-data --threshold 0.5 --label signal
ria annotate cusum capture.sigmf-data --min-duration 5
ria annotate separate capture.sigmf-data --indices 0,1 --verbose
Example output:
ria annotate list
Inspect all annotations with --verbose:
$ ria annotate list sample_recording3_annotated.npy --verbose
Annotations in sample_recording3_annotated.npy:
[0] Samples 170,599-171,116: signal
Type: standalone
Frequency: 3.41 GHz - 3.41 GHz
Detail: {'generator': 'energy_detector', 'freq_method': 'nbw'}
[1] Samples 182,310-182,841: signal
Type: standalone
Frequency: 3.41 GHz - 3.41 GHz
Detail: {'generator': 'energy_detector', 'freq_method': 'nbw'}
[2] Samples 1,133,165-1,133,706: signal
...
[7] Samples 2,113,268-2,861,395: signal
Type: standalone
Frequency: 3.41 GHz - 3.41 GHz
Detail: {'generator': 'energy_detector', 'freq_method': 'nbw'}
Total: 8 annotation(s)
ria annotate add
Add a single annotation by sample index:
$ ria annotate add sample_recording3_annotated.npy --start 50000 --count 10000 --label burst -o out.npy
Loaded: sample_recording3_annotated.npy
Adding annotation:
Start: 50,000
Count: 10,000 samples
Frequency: full bandwidth
Label: burst
Type: standalone
Saving to: out.npy
✓ Saved
ria annotate remove
Remove one annotation by its list index (run annotate list first to confirm):
$ ria annotate remove sample_recording3_annotated.npy 0 -o out.npy
Loaded: sample_recording3_annotated.npy
Removing annotation [0]:
Removed: samples 170,599-171,116 (signal)
Saving to: out.npy
✓ Saved
ria annotate clear
Remove all annotations at once:
$ ria annotate clear sample_recording3_annotated.npy --force --overwrite
Loaded: sample_recording3_annotated.npy
Cleared 8 annotation(s)
Saving to: sample_recording3_annotated.npy
✓ Saved
ria annotate energy
Auto-detect signal regions above the noise floor:
$ ria annotate energy sample_recording3.npy --label signal -o sample_recording3_annotated.npy
Loaded: sample_recording3.npy
Detecting signals using energy-based method...
Time detection:
Segments: 10
Threshold: 1.2x noise floor
Window size: 200 samples
Min distance: 5000 samples
Frequency bounds: nbw
✓ Added 8 annotation(s)
Saving to: sample_recording3_annotated.npy
✓ Saved
ria annotate energy sample_recording3.npy --label signal
ria annotate threshold
Detect regions above a fixed fraction of peak magnitude:
$ ria annotate threshold sample_recording3.npy --threshold 0.7 --label strong -o out.npy
Loaded: sample_recording3.npy
Detecting signals using threshold qualifier...
Threshold: 70.0% of max magnitude
Window size: auto (1ms)
Channel: 0
✓ Added 2 annotation(s)
Saving to: out.npy
✓ Saved
ria annotate threshold sample_recording3.npy --threshold 0.7 --label strong
ria annotate cusum
Detect regime changes using change-point detection:
$ ria annotate cusum sample_recording3.npy --label regime -o out.npy
Loaded: sample_recording3.npy
Detecting segments using CUSUM...
Min duration: 5.0 ms
✓ Added 37 annotation(s)
Saving to: out.npy
✓ Saved
ria annotate cusum sample_recording3.npy --label regime
ria annotate separate
separate takes existing annotations as input and splits each one into narrower
sub-band annotations by finding distinct spectral peaks within the annotated time window.
The typical workflow is to first run threshold (or energy) to mark signal regions,
then run separate to resolve the individual frequency components within them.
Step 1 — create broad annotations with threshold:
$ ria annotate threshold sample_recording5.npy --threshold 0.5 --label signal -o annotated.npy
Loaded: sample_recording5.npy
Detecting signals using threshold qualifier...
Threshold: 50.0% of max magnitude
Window size: auto (1ms)
Channel: 0
✓ Added 3 annotation(s)
Saving to: annotated.npy
✓ Saved
Step 2 — run separate to split by frequency component:
$ ria annotate separate annotated.npy -o separated.npy
Loaded: annotated.npy
Splitting annotations by frequency components...
Input annotations: 3
FFT size: 65536
Noise threshold: auto-estimated
Min component BW: 50.00 kHz
✓ Output annotations: 6 (+3 change)
Saving to: separated.npy
✓ Saved
After separate — each annotation is resolved into upper and lower frequency components
4.6 convert
Purpose:
Convert between
sigmf,npy,wav, andblue.Normalize datasets into the format required by downstream tooling or collaboration targets.
Usage:
ria convert <input> [output] [options]
If output is omitted, --format must be provided. If both are given, format is
inferred from the output file extension.
Options:
--format {npy,sigmf,wav,blue}--output-dir--legacy: use older NPY loader behavior for historical recordings.--wav-sample-rate: target sample rate for WAV export.--wav-bits {16,32}: output PCM depth; higher preserves more dynamic range.--blue-format {CI,CF,CD}: Bluefile complex sample representation.--metadata KEY=VALUE(repeatable): add or override metadata during conversion; especially useful when exporting to SigMF.--overwrite,-v/--verbose,-q/--quiet
Examples:
ria convert recording.sigmf-data output.npy
ria convert recording.npy --format sigmf
ria convert highrate.npy audio.wav --wav-sample-rate 48000
ria convert old.npy --format sigmf --legacy --overwrite
Example output:
$ ria convert sample_recording3.npy sample_recording3.sigmf-data
Converting: sample_recording3.npy → sample_recording3.sigmf-data
Input format: NPY
Output format: SIGMF
Samples: 3,000,000
Conversion complete: sample_recording3.sigmf-data, sample_recording3.sigmf-meta
4.7 split
Purpose:
Split, trim, or extract recordings.
Create manageable dataset shards or extract windows of interest without custom scripts.
Usage:
ria split <input> [operation] [options]
Choose exactly one operation per invocation:
--split-at <sample>: binary split at a specific sample index.--split-every <N>: fixed-size chunking for ML pipelines.--split-duration <seconds>: time-based chunking.--trim(with--start+--lengthor--end): extract one sub-window.--extract-annotations: write each annotated region as a standalone file.
Trim controls: --start, --length, --end
Annotation extraction filters: --annotation-label, --annotation-index
Output controls:
--output-dir, --output-prefix, --output-format {npy,sigmf,wav,blue},
--overwrite, --legacy, -v / --verbose, -q / --quiet
Examples:
ria split recording.sigmf-data --split-at 500000 --output-dir out
ria split recording.sigmf-data --split-every 100000 --output-dir chunks
ria split recording.sigmf-data --split-duration 1.0 --output-dir chunks
ria split recording.npy --trim --start 1000 --length 5000 --output-dir trimmed
ria split annotated.sigmf-data --extract-annotations --annotation-label payload
Example output:
$ ria split sample_recording3.npy --split-every 500000 --output-dir chunks
Loading: sample_recording3.npy
Total samples: 3,000,000
Splitting into chunks of 500,000 samples...
Creating 6 chunks...
Chunk 1/6: samples 0-499,999...
Chunk 2/6: samples 500,000-999,999...
Chunk 3/6: samples 1,000,000-1,499,999...
Chunk 4/6: samples 1,500,000-1,999,999...
Chunk 5/6: samples 2,000,000-2,499,999...
Chunk 6/6: samples 2,500,000-2,999,999...
Created 6 chunks in chunks/
4.8 combine
Purpose:
Merge multiple recordings by concatenation or sample-wise addition.
Assemble multi-part captures or synthesize mixtures for testing and model training.
Usage:
ria combine <input1> <input2> [input3 ...] <output> [options]
Options:
--mode {concat,add}--align-mode {error,truncate,pad,pad-start,pad-center,pad-end,repeat,repeat-spaced}--pad-start-sample,--repeat-spacing--normalize: rescale combined output to avoid clipping/saturation after addition.--output-format {sigmf,npy,wav,blue}--overwrite,--metadata KEY=VALUE(repeatable)--legacy,--verbose,--quiet
--mode concat appends inputs sequentially in time. --mode add performs sample-wise
summation and requires all inputs to be the same length, or an --align-mode to
reconcile length differences:
error: fail if lengths differ.truncate: cut all to shortest length.pad,pad-start,pad-center,pad-end: zero-pad shorter streams.repeat: tile shorter streams to match longest.repeat-spaced: repeated placement with spacing via--repeat-spacing.
Examples:
ria combine a.npy b.npy c.npy merged.npy
ria combine signal.npy noise.npy noisy.npy --mode add
ria combine long.npy short.npy out.npy --mode add --align-mode pad-center
ria combine signal.npy pattern.npy out.npy --mode add --align-mode repeat-spaced --repeat-spacing 10000
Example output:
$ ria combine sample_recording3.npy qam64_35.npy combined.npy
Combining 2 recordings (concat mode)...
Saved to: combined.npy
4.9 generate group (and synth alias)
Purpose:
Generate synthetic IQ signals and save in
npy,sigmf,wav, orblue.Create known-reference waveforms and synthetic datasets for validation, demos, and ML data generation.
ria synth ... is an alias for ria generate ....
Usage:
ria generate <subcommand> [subcommand options] [common options]
Available subcommands:
Subcommand(s) |
Description |
|---|---|
|
Clean sinusoidal calibration/reference source |
|
Baseline noise floor data or controlled additive-noise synthesis |
|
Sweep-based radar/sonar-style signals and bandwidth occupancy tests |
|
Periodic waveform primitives |
|
Digital modulation families with pulse-shaping filter support |
|
Frequency-shift keying with configurable tone spacing |
|
On-off keying and continuous-phase modulation schemes |
Common options (all subcommands):
-s, --sample-rate(required),-n, --num-samplesor-t, --duration-o, --output(required),-F / --format {npy,sigmf,wav,blue}--frequency-shift,--center-frequency: separate baseband shape from RF metadata.--add-noise,--noise-power,--path-gain: apply noise post-generation.--multipath-paths,--multipath-max-delay,--iq-amp-imbalance,--iq-phase-imbalance,--iq-dc-offset: channel and IQ impairments.--config <yaml>,-w / --overwrite,-m / --metadata KEY=VALUE,-v / --verbose,-q / --quiet
Subcommand options:
Subcommand |
Unique options |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Examples:
ria generate tone -s 2e6 -n 500000 --frequency 50e3 -o tone.sigmf-data
ria generate noise -s 2e6 -n 500000 --noise-type gaussian --power 0.05 -o noise.npy
ria generate chirp -s 5e6 -t 0.5 --bandwidth 2e6 --period 0.01 --type up -o chirp.sigmf-data
ria generate qam -s 2e6 -r 100e3 -M 16 -N 5000 --message-source random -o qam16.npy
ria synth psk -s 2e6 -r 100e3 -M 8 -N 8000 -o psk8.npy
Example output:
$ ria generate tone -s 2e6 -n 100000 --frequency 50e3 -o tone.npy
Generating tone: 50.00 kHz at 2.00 MS/s
$ ria generate qam -s 2e6 -n 50000 --order 16 --symbol-rate 100e3 --message-source random -o qam16.npy
Generating QAM-16 (2500 symbols)...
4.10 transform group
Purpose:
Apply algorithmic transforms to existing recordings.
Run reusable augmentations/impairments for dataset diversity and robustness testing.
Usage:
ria transform <augment|impair|custom> ...
augment
ria transform augment [augmentation] [input] [output] [options]
Applies transforms from iq_augmentations (dataset-expansion style modifications).
Options: --list, --help-transform, --params KEY=VALUE (repeatable), --view,
--overwrite, -v / --verbose, -q / --quiet
impair
ria transform impair [impairment] [input] [output] [options]
Applies transforms from iq_impairments (noise, distortion, and channel degradation
effects). Same options as augment.
custom
ria transform custom [transform_name] [input] [output] --transform-dir <dir> [options]
Dynamically loads public functions from Python files in --transform-dir and exposes them
as callable transforms.
Options: --transform-dir (required), --list, --help-transform,
--params KEY=VALUE (repeatable), --view, --overwrite, -v / --verbose,
-q / --quiet
--params values must be KEY=VALUE; types are inferred as int, float, or string.
Use --list to enumerate available transform names, and --help-transform <name> to
inspect parameter hints. --view writes a PNG preview alongside transform output.
Examples:
ria transform augment --list
ria transform augment channel_swap in.npy out.npy
ria transform augment drop_samples in.npy --params max_section_size=5 --view
ria transform impair --list
ria transform impair add_awgn_to_signal in.npy out.npy --params snr=10
ria transform custom --transform-dir ./my_transforms --list
ria transform custom my_filter in.npy out.npy --transform-dir ./my_transforms --params cutoff=0.2
Example output:
List available augmentations:
$ ria transform augment --list
Available augmentations:
amplitude_reversal Negates the amplitudes of both the I and Q data samples
channel_swap Switches the I (In-phase) with the Q (Quadrature) data samples
cut_out Cuts out random sections of IQ data and replaces them with zeros
drop_samples Randomly drops IQ data samples
generate_awgn Generates additive white gaussian noise relative to the SNR
magnitude_rescale Selects a random starting point and multiplies IQ data by a scalar
patch_shuffle Selects random patches and shuffles the data samples within them
quantize_parts Quantizes random parts of the IQ data by a few bits
quantize_tape Quantizes the IQ data by a few bits
spectral_inversion Negates the imaginary components (Q) of the data samples
time_reversal Reverses the order of I and Q data samples along the time axis
Apply an impairment (AWGN at SNR=10 dB):
$ ria transform impair add_awgn_to_signal sample_recording3.npy sample_recording3_awgn.npy --params snr=10
Impairing: sample_recording3.npy → sample_recording3_awgn.npy
Saved to: sample_recording3_awgn.npy
sample_recording3.npy after add_awgn_to_signal --params snr=10
4.11 transmit
Purpose:
Transmit IQ via a TX-capable SDR (
pluto,hackrf,bladerf,usrp).Support playback of captured/generated waveforms for over-the-air or wired-loop test scenarios.
Usage:
ria transmit [options]
If neither --input nor --generate is specified, the command defaults to a generated
LFM waveform.
Options:
-d/--device {pluto,hackrf,bladerf,usrp},-i/--ident,-c/--config-s/--sample-rate,-f/--center-frequency,-g/--gain,-b/--bandwidth--input <file>: transmit an existing recording.--generate {lfm,chirp,sine,pulse}: synthesize a signal on the fly.--legacy: use older NPY loader for historical recordings.-r, --repeat: transmit the input a fixed number of times.--continuous: transmit until interrupted (Ctrl+C).--tx-delay: pause between repeats when--repeatis used.-y, --yes: skip confirmation prompts; use carefully in scripted environments.-v/--verbose,-q/--quiet
Warning
--continuous transmits until manually interrupted. Validate gain settings, antenna
configuration, and regulatory compliance before use.
Examples:
ria transmit -d pluto -f 915e6 -s 2e6 --input capture.sigmf-data
ria transmit -d hackrf --generate lfm -f 2.44G --continuous
ria transmit -d usrp --input msg.npy -r 3 --tx-delay 0.5
Example output:
Note
transmit requires a TX-capable SDR. The following shows representative output for a
PlutoSDR playback.
$ ria transmit -d pluto -f 915e6 -s 2e6 --input capture.sigmf-data
Initializing PlutoSDR...
URI: ip:192.168.2.1
Center frequency: 915.00 MHz
Sample rate: 2.00 MS/s
Gain: 0 dB
Transmitting capture.sigmf-data (500,000 samples)...
Transmit complete.
5) YAML Config Patterns
Several commands accept --config <file.yaml> for parameter loading. CLI flags generally
override values loaded from --config.
Keep one stable baseline YAML per workflow (capture, generate, transmit), then override only experiment-specific fields on the CLI.
Capture config example:
device: pluto
ident: 192.168.2.1
sample_rate: 2000000
center_frequency: 2.44G
gain: 20
bandwidth: 2000000
num_samples: 500000
format: sigmf
output: run1.sigmf-data
metadata:
campaign: lab_eval
antenna: dipole
ria capture -c capture.yaml
Generate config example:
sample_rate: 2000000
num_samples: 200000
format: npy
output: synth.npy
noise_power: 0.02
ria generate noise --config generate.yaml
6) Brief Scripting (Python) Preview
For quick non-CLI use:
from ria_toolkit_oss.data import Recording
from ria_toolkit_oss.io import load_recording, to_sigmf
from ria_toolkit_oss.transforms import iq_augmentations, iq_impairments
rec = load_recording("capture.sigmf-data")
aug = iq_augmentations.channel_swap(rec)
imp = iq_impairments.add_awgn_to_signal(aug, snr=10)
to_sigmf(imp, filename="capture_awgn", path=".")
You can also call annotation algorithms and block-generator primitives from Python directly.