Software-defined radio experiments on COSMOS — from a single tone between two radios up to a full bit-error-rate waterfall measured on hardware.
COSMOS and ORBIT carry several families of SDR, from USB-attached entry-level kits to 10 G-attached platforms with on-board FPGAs and their own embedded computing. The ones you are most likely to meet in these tutorials:
| Device | What it is | Host link | Typical use here |
|---|---|---|---|
| B210 | Compact USB SDR, 70 MHz – 6 GHz, 1 TX + 1 RX, up to 56 MS/s | USB 3.0 | Most two-node experiments; the default choice for prototyping |
| B205mini | Single-channel board in the same B2xx family | USB 3.0 | The sb4 pair, behind the RF matrix |
| X310 | 1U, dual-channel, 200 MS/s, RFNoC FPGA | Dual SFP+ 10 GbE | High-rate capture, RFNoC work |
| USRP-2974 | An X310 and a Dell-class mini-PC in one box, joined over PCIe | PCIe (internal) | Rooftop and FR3 experiments; the host is the radio |
| N310 | 4-channel, embedded ARM, dual 10 G | 10 GbE | Coherent multi-channel capture, 5G NR |
| N210 | 1U single-channel with a daughterboard slot | Gigabit Ethernet | Legacy grid experiments |
| E312 | Battery-powered, fully standalone | — | Untethered field experiments |
All of them are driven through Ettus's UHD. The baseline-sdr.ndz node image ships UHD 4.9 and GNU Radio 3.10 already built and matched to the FPGA images, so uhd_find_devices on a freshly loaded node should enumerate your radio without any further setup.
Always load
baseline-sdr.ndz, never the versioned image it points to. It is a symlink, repointed when the reference image is rebuilt, so a tutorial written against it keeps working across image generations.
Full details per device: SDRs overview. For the RF front-ends between radio and antenna, see RF front-end.
The sandboxes below are the ones the tutorials on this page are written and tested against. They differ in what sits between the two radios, and that choice matters more than the radio model for most experiments.
| Sandbox | Radios | Path between them | Good for |
|---|---|---|---|
| grid | 8 × B210, 4 × X310, plus legacy N210 / USRP1 | Over the air, inside the shielded grid | Realistic multipath; nodes far apart |
| sb1 | 8 × USRP-2974, including the sdr1/sdr2-piradio pair behind Pi-Radio FR3 front-ends |
Over the air at 10.3 GHz through the FR3 chain | FR3, mmWave-adjacent work, upconverter experiments |
| sb4 | B205mini on node1-3 … node1-6 |
Coax through a JFW programmable attenuator matrix, 0–95 dB in 1 dB steps plus ~20 dB fixed insertion loss | Repeatable path loss; the cleanest waterfalls |
| sb5 | 2 × B210 (node1-1, node1-2) |
Coax through a fixed 60 dB attenuator | A quiet, stable, radiation-free two-node link |
| sb6 | 2 × X310, one cabled to each host over a private 10 GbE run | Coax through a fixed 60 dB attenuator | A second cabled pair, with more transmit power than the B210s — and wired to its radios differently from the grid, see below |
| sb7 | 2 × N210 (SBXv3, 400 MHz – 4.4 GHz) | Coax through a fixed 20 dB attenuator — much less loss than sb5/sb6 | The older USRP2 generation. The orchestrated OFDM BER experiment does not yet decode here — see the note below before planning work on it |
| bed | 5 × USRP-2974 / N310 class | Rooftop, over the air (NYC) | Outdoor propagation, long links |
On the grid, the B210s sit at node3-2, node3-19, node8-7, node8-14, node13-7, node13-14, node18-2, node18-19 — those are USB-attached to the node they are named for.
The grid X310s are not attached to a node at all. They live in MIMO racks in the four corners of the grid, eight positions each, and are their own kind of testbed resource — rfdevice, not node. They occupy four address blocks:
Twenty-four X310s are installed, eight per rack. On 2026-08-03 a live sweep found nineteen answering, spread across the address blocks like this:
| Addresses | Answering 2026-08-03 |
|---|---|
| 10.10.23.1–8 | 23-4 23-5 23-6 23-7 23-8 |
| 10.10.23.11–18 | 23-14 23-18 |
| 10.10.24.1–8 | 24-1 24-3 24-4 24-5 24-6 24-7 24-8 |
| 10.10.24.11–18 | 24-11 24-12 24-15 24-16 24-17 |
Do not plan an experiment from that table — probe. Five radios were down that day, and the inventory service's own cached scan (last run in March) lists twenty-two, disagreeing with the live sweep in both directions. Radios go up and down; the number that matters is the one you measure at the moment you run:
# on any grid node - sweep both racks and see what is really there
for r in 23 24; do for i in $(seq 1 20); do
uhd_find_devices --args="addr=10.10.$r.$i" 2>/dev/null | grep -q serial \
&& echo "node$r-$i is up"
done; done
The node23-* rack carries UBX160 daughterboards. They are embedded ZPU devices with no host operating system — INF_pxe_image is NA and omf load does not apply to them — so you drive one from a compute node over the control network:
# on any grid node, with the radio pinned by address
uhd_find_devices --args="addr=10.10.23.7"
Because every grid node can reach every rack X310, an experiment must pin the address, or both ends of a two-node link can end up talking to the same radio and produce a confident measurement of nothing. The experiments here use node23-7 (10.10.23.7) and node23-4 (10.10.23.4), driven from node3-1 and node3-20.
On sb4 the SDR is not on the matrix port of the same number — the feeds are node1-3 → ports 1/2, node1-4 → 3/4, node1-5 → 5/6, node1-6 → 7/8.
Not every X310 is reached the same way, and the difference is invisible until it bites. On the grid the X310s sit on the node control plane, so any node can see all of them and uhd_find_devices just works — which is why an experiment there has to pin an address, or both ends may grab the same radio. On sb6 each X310 is cabled point-to-point to its own host's SFP+ port instead. That port comes up with no address, so uhd_find_devices reports No UHD Devices Found on a perfectly healthy node with a perfectly healthy radio. Give the port an address on the radio's subnet and it appears:
root@node1-2:~# ip addr add 192.168.40.1/24 dev enp1s0 && ip link set enp1s0 up
root@node1-2:~# uhd_find_devices --args="addr=192.168.40.2"
type: x300
serial: 30F10F9
Both sb6 radios answer on that same address, 192.168.40.2 — the X310 factory default — because each is alone on its own run and there is nothing to disambiguate. The orchestrated experiments handle this for you: sdr/ofdm-ber-sb6-x310.description.yml sets cosmos_fr3_data_link_addr and the role brings the link up before it goes looking for a radio.
On sb7 the N210s are a known-incomplete target. The radios themselves are healthy and the link is strong — a transmitted OFDM signal arrives about 64 dB above the receiver's noise floor — but the orchestrated BER receiver synchronises on nothing, at any SNR. Two causes were found and fixed along the way, and both are worth knowing if you write your own flowgraph for this generation of radio:
internal as a time source. The valid values are none, external, _external_ and mimo. GNU Radio Companion offers "Internal" in the dropdown regardless of the radio.set_time_unknown_pps() blocks forever on a radio with no PPS input, then raises Board 0 may not be getting a PPS signal. GRC emits this call whenever the block's sync option is set to "Unknown PPS".Both kill the flowgraph at construction, so the error you see is usually something unrelated several steps later. Two independent radios measuring a BER do not need a common time base — leave the sync option at "don't sync".
Three of these are cabled, and the attenuator value is part of the experiment.
sb5andsb6each put a fixed 60 dB pad between the two radios;sb7has only 20 dB, so the same transmit settings deliver roughly 40 dB more signal there and will overdrive a receiver that was set up for the other two.sb4is cabled through a programmable matrix instead, which is what makes it the one sandbox where path loss is a swept variable rather than a fixed property. Onlygridradiates over the air.This table covers the sandboxes these tutorials are verified on; it is not the complete fleet inventory. For per-node placement across the whole grid and all sandboxes see the USRP deployment maps — though note that page is currently behind on several sandboxes, so trust a live
uhd_find_devicesover any written map.
How each tutorial runs — the badge on every page's At a glance table:
| Interactive | You drive it by hand — open a flowgraph, press play, change something, watch what happens. Best for learning what a knob does. |
| Automated | One cosmos-run <description> command does the whole thing: imaging, configuration, the experiment, collection and teardown. |
| Automated only | As above, and there is deliberately no by-hand version — the experiment is a sweep of twenty-odd points with per-point settling and accumulation, and a hand walkthrough would have to drop most of it. |
| Manual | Older pages, step by step, predating the orchestration. Still instructive; expect to adapt commands. |
Many pages are both interactive and automated, which is the ideal: see it once by hand, then let the sweep produce the curve.
Orchestrated with Ansible through cosmos-run, and verified on the current baseline-sdr.ndz image. Start here.
| Tutorial | About | Last verified |
|---|---|---|
| Two-Node Digital-Modulation BER Experiments · automated | BER-vs-Eb/N0 for BPSK/QPSK on two B210s with stock GNU Radio 3.10 — headless, SigMF output, a generic plotter, and one description that runs unchanged on grid, sb4 and sb5. |
2026-07-29 |
| OFDM BER at FR1 (sub-6 GHz) — a three-mechanism laboratory · interactive + automated | A full OFDM waterfall measured three different ways — injected noise, a programmable attenuator, and transmit power — interactively in GNU Radio Companion and under Ansible. Covers why the three disagree about what is easy to measure. | 2026-08-01 |
| Build an FM Broadcast Station — Stereo and RDS from First Principles · interactive | Transmit a complete stereo FM broadcast with RDS between two sb6 nodes and listen live in your browser while the station name appears. Builds both ends, so it explains why the pilot is at 19 kHz and why RDS needs no carrier recovery. | 2026-08-05 |
| Receiving ADS-B Aircraft Transponders with a USRP B210 · automated | Decode live 1090 MHz aircraft transponders on a grid B210 by building and running readsb through SoapyUHD, driven by a playbook. |
2026-07-28 |
Also SDR, filed under FR3 — the five-modulation sweep, at FR3 or FR1: OFDM BER Across Five Subcarrier Modulations · automated only — BPSK through 64-QAM over the sb1 FR3 chain, swept by transmit power, and the same experiment on a plain USRP pair. It is the companion to the OFDM laboratory above: that page covers the PSK family graphically, this one covers all five modulations under Ansible — including at 2 GHz on the grid X310 pair, where 64-QAM reaches 8.5 × 10⁻⁶.
Kept because they still work and still teach something, but not part of the Ansible-orchestrated set: they predate it, are verified against older images, or were written for hardware that has since moved. Expect to adapt node names, image names and commands. Where one of these overlaps a current tutorial above, prefer the current one.
| Tutorial | About |
|---|---|
| A Two-Node LoRa Link on COSMOS | Build the LoRa PHY on two nodes, send CRC-checked frames at 915 MHz, then measure where the link breaks by sweeping transmit power through the sb4 attenuator matrix. |
| PSK BER — BPSK / QPSK / 8PSK | The earlier PSK BER page, written against the previous cosmos-ansible bundle model. Superseded for most purposes by the two BER pages above. |
| QAM BER Experiments | Placeholder for single-carrier QAM; same older bundle model. |
| GNU Radio CFO Estimation with OFDM and IBM 28 GHz mmWave (USRP N310) | Estimate carrier frequency offset between a pair of N310s in sb1 using GNU Radio OFDM flowgraphs. |
| GNU Radio OFDM Data Transfer with USRP X310 | Transfer data between two X310s using GNU Radio OFDM flowgraphs, in both GUI and headless Python modes. |
| Spectrum Sensing with USRP2974 | Real-time spectrum sensing on a USRP-2974 in the BED domain, visualised in a browser. |
| Spectrum Visualization with RFNoC Fosphor | FPGA-accelerated spectrum visualisation on a USRP-2974 using the RFNoC Fosphor block in GNU Radio Companion. |
| Using Two RFNoC Streams Simultaneously on a Single USRP X310 | Two concurrent RFNoC streams (TX and RX) on one X310, on the grid. |
| Working with USRP X310 and GNU Radio | Transmit and receive a 1 MHz cosine over the air between two X310s. |
Part of the COSMOS Tutorials collection.