New tool (tools/rf_testbench.py) automates five test sequences using a NanoVNA as a CW source and HMC472A digital attenuator (0-31.5 dB, 0.5 dB steps via REST API) to characterize the SkyWalker-1 receiver: - AGC linearity mapping across 64 attenuation steps - IF band flatness sweep (950-1500 MHz) - Frequency accuracy via peak detection - Minimum detectable signal search - BPSK mode 9 CW probe (Viterbi rate 1/2 K=7) Includes SKYWALKER_MOCK=1 mode, path-loss calibration from NanoVNA S21 sweeps, and safe-state cleanup (attenuator to max on exit, LNB power never enabled in direct-input mode). Also adds Applications & Use Cases guide, RF Test Bench docs page, fixes h21cm cable loss (was 3x too high), and updates sidebar.
261 lines
11 KiB
Plaintext
261 lines
11 KiB
Plaintext
---
|
|
title: RF Test Bench
|
|
description: Automated CW injection testing with NanoVNA, HMC472A digital attenuator, and SkyWalker-1 receiver.
|
|
---
|
|
|
|
import { Aside, Badge, Card, CardGrid, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
|
|
<Badge text="tools/rf_testbench.py" variant="note" />
|
|
|
|
The `rf_testbench.py` tool turns a NanoVNA, an HMC472A digital attenuator, and the SkyWalker-1 into
|
|
an automated RF test bench. It injects CW signals at known frequencies and power levels, then
|
|
measures the receiver's response — characterizing AGC linearity, IF band flatness, frequency
|
|
accuracy, sensitivity, and BPSK mode 9 behavior.
|
|
|
|
## Hardware Setup
|
|
|
|
<Steps>
|
|
1. **NanoVNA CH0 output** (SMA) connects to a **DC blocker** (SMA inline, required)
|
|
2. **DC blocker output** connects to the **HMC472A RF IN** (SMA)
|
|
3. **HMC472A RF OUT** (SMA) connects via **SMA-to-F adapter** to the **SkyWalker-1 F-connector**
|
|
4. **HMC472A ESP32-S2 controller** connected to your network (WiFi) — reachable at `http://attenuator.local`
|
|
5. **NanoVNA** connected via USB (for mcnanovna automation) or operated via touchscreen (manual mode)
|
|
</Steps>
|
|
|
|
```
|
|
NanoVNA CH0 ──→ DC Blocker ──→ HMC472A (0-31.5 dB) ──→ SMA-to-F ──→ SkyWalker-1
|
|
(SMA) (SMA) REST API control adapter (F-type)
|
|
http://attenuator.local
|
|
```
|
|
|
|
### Components
|
|
|
|
| Component | Purpose | Notes |
|
|
|-----------|---------|-------|
|
|
| NanoVNA-H (9 kHz-1.5 GHz) | CW signal source | Output ~-15 dBm at max power. Overlaps SkyWalker-1 IF band at 950-1500 MHz |
|
|
| DC Blocker (SMA inline) | Protect NanoVNA from LNB voltage | Required — even though the tool disables LNB power, this prevents accidental damage |
|
|
| HMC472A attenuator module | Precision level control | 0-31.5 dB in 0.5 dB steps, controlled via ESP32-S2 REST API |
|
|
| SMA-to-F adapter | Connector transition | 50-to-75 ohm mismatch is ~0.2 dB — negligible |
|
|
|
|
<Aside type="danger" title="DC blocker is required">
|
|
The SkyWalker-1 can supply 13-18V DC through the F-connector for LNB power. Although `rf_testbench.py`
|
|
disables LNB power on startup, a bug, power glitch, or running a different tool without disconnecting
|
|
could send DC voltage backward through the signal path. The DC blocker prevents this from reaching
|
|
the HMC472A and NanoVNA.
|
|
</Aside>
|
|
|
|
### HMC472A Attenuator
|
|
|
|
The [HMC472A digital attenuator](https://hmc472.l.zmesh.systems/) provides programmable signal level
|
|
control via its ESP32-S2 REST API:
|
|
|
|
- **Range**: 0 to 31.5 dB in 0.5 dB steps (64 discrete settings)
|
|
- **Bandwidth**: DC to 3.8 GHz (covers the full SkyWalker-1 IF range)
|
|
- **Insertion loss**: 1.4-1.9 dB typical
|
|
- **Control**: HTTP REST — `POST /set {"attenuation_db": 10.5}`
|
|
- **Switching speed**: 60 ns (faster than any measurement cycle)
|
|
|
|
The tool communicates with the attenuator at `http://attenuator.local` by default. Override with
|
|
`--attenuator http://10.0.0.50` if your device has a different address.
|
|
|
|
### NanoVNA Frequency Overlap
|
|
|
|
The NanoVNA-H (HW3.7) covers 9 kHz to 1.5 GHz. The SkyWalker-1's IF range is 950-2150 MHz.
|
|
The **overlapping usable range is 950-1500 MHz** — the lower portion of the IF band. This is
|
|
sufficient for characterizing the tuner and AGC, and includes the 1420 MHz hydrogen line region.
|
|
|
|
For testing above 1500 MHz, a different signal source (bladeRF, signal generator) would be needed.
|
|
|
|
## Calibration
|
|
|
|
Before running quantitative tests, characterize the signal path loss:
|
|
|
|
<Steps>
|
|
1. Disconnect the SkyWalker-1 end of the cable
|
|
2. Connect: **NanoVNA CH0** → DC blocker → HMC472A (set to 0 dB) → cable → **NanoVNA CH1**
|
|
3. Run an S21 sweep from 950 to 1500 MHz using mcnanovna or the NanoVNA touchscreen
|
|
4. Export as CSV with columns `freq_mhz` and `s21_db` (or `frequency_hz` and `loss_db`)
|
|
5. Pass to `rf_testbench.py` with `--cal path_loss.csv`
|
|
</Steps>
|
|
|
|
The tool interpolates the measured path loss at each test frequency and subtracts it from AGC
|
|
readings. Without a calibration file, raw AGC values are still reported — useful for relative
|
|
measurements but not calibrated to absolute power.
|
|
|
|
<Aside type="tip" title="HMC472A insertion loss">
|
|
The HMC472A adds 1.4-1.9 dB of insertion loss even at 0 dB attenuation setting. The calibration
|
|
sweep captures this automatically since the signal passes through the attenuator during the S21
|
|
measurement.
|
|
</Aside>
|
|
|
|
## Prerequisites
|
|
|
|
- **SkyWalker-1** with [custom firmware v3.02+](/firmware/custom-v302/) (for `tune_monitor` command)
|
|
- **HMC472A** attenuator with ESP32-S2 controller on the network
|
|
- **NanoVNA-H** (manual mode works with any VNA; auto mode requires [mcnanovna](https://git.supported.systems/rf/mcnanovna))
|
|
- **Python 3.10+** with `pyusb` installed
|
|
- **DC blocker** (SMA inline)
|
|
- **SMA-to-F adapter**
|
|
|
|
## Test Descriptions
|
|
|
|
### AGC Power Linearity
|
|
|
|
```bash
|
|
python tools/rf_testbench.py agc-linearity --freq 1200
|
|
```
|
|
|
|
Injects CW at a fixed frequency while sweeping the HMC472A from 0 to 31.5 dB in 0.5 dB steps.
|
|
At each attenuation level, the SkyWalker-1 reports AGC1, AGC2, and derived power. This maps the
|
|
**AGC transfer function** — how the receiver's automatic gain control responds to known changes
|
|
in input power.
|
|
|
|
The output shows whether the AGC is linear, where it saturates, and its effective dynamic range.
|
|
With 64 measurement points across 31.5 dB, the resolution is high enough to reveal nonlinearities
|
|
in the BCM3440 tuner's gain control loop.
|
|
|
|
### IF Band Flatness
|
|
|
|
```bash
|
|
python tools/rf_testbench.py band-flatness --start 950 --stop 1500 --step 10
|
|
```
|
|
|
|
Sweeps the NanoVNA CW frequency across the IF band while keeping the HMC472A at a fixed
|
|
attenuation (10 dB default). At each frequency, the SkyWalker-1 tunes and reads AGC power.
|
|
|
|
The result reveals:
|
|
- **Tuner gain slope**: the BCM3440 may have more gain at some frequencies than others
|
|
- **Passband ripple**: resonances or nulls in the IF filter chain
|
|
- **Cable/path frequency response**: if a calibration file is loaded, this is subtracted out
|
|
|
|
### Frequency Accuracy
|
|
|
|
```bash
|
|
python tools/rf_testbench.py freq-accuracy --freqs 1000,1100,1200,1300,1400
|
|
```
|
|
|
|
At each test frequency, the NanoVNA injects CW while the SkyWalker-1 runs a narrow spectrum
|
|
sweep (+/- 5 MHz) around the expected frequency. The detected power peak is compared against the
|
|
injected frequency.
|
|
|
|
This characterizes the **BCM3440 tuner's frequency accuracy** — how much the actual tuned
|
|
frequency differs from the commanded frequency. The error may be systematic (constant offset)
|
|
or frequency-dependent.
|
|
|
|
### Minimum Detectable Signal
|
|
|
|
```bash
|
|
python tools/rf_testbench.py mds --freq 1200
|
|
```
|
|
|
|
First measures the noise floor with maximum attenuation (31.5 dB). Then injects CW and steps
|
|
the HMC472A from 0 dB upward in 1 dB increments until the signal drops below 3-sigma above
|
|
the noise floor.
|
|
|
|
The attenuation level where the signal disappears, combined with the NanoVNA output power
|
|
(~-15 dBm), gives an approximate **minimum detectable signal level** in dBm.
|
|
|
|
### BPSK Mode 9 CW Probe
|
|
|
|
```bash
|
|
python tools/rf_testbench.py bpsk-probe --freq 1200
|
|
```
|
|
|
|
An exploratory test that tunes the SkyWalker-1 in **BPSK mode (index 9)** — the same Viterbi
|
|
rate 1/2 K=7 inner FEC used by GOES LRIT. A CW carrier has no modulation, so the demodulator
|
|
shouldn't acquire lock, but the AGC and carrier recovery behavior is informative.
|
|
|
|
Tests several symbol rates (293,883 sps matching LRIT, plus 500K, 1M, and 5M) and compares
|
|
against QPSK mode 0 at the same frequency. This establishes a baseline for what mode 9 reports
|
|
with an unmodulated carrier — useful context for future modulated-signal experiments with a
|
|
bladeRF.
|
|
|
|
## Options
|
|
|
|
| Flag | Default | Description |
|
|
|------|---------|-------------|
|
|
| `--attenuator` | `http://attenuator.local` | HMC472A REST API base URL |
|
|
| `--nanovna` | `auto` | NanoVNA control: `auto` (mcnanovna) or `manual` (prompted) |
|
|
| `--cal` | — | Path loss calibration CSV file |
|
|
| `--settle` | 200 | Settle time in ms after changing attenuation |
|
|
| `--output` / `-o` | — | CSV output file |
|
|
| `--verbose` / `-v` | — | Show raw USB traffic |
|
|
|
|
### Per-Test Options
|
|
|
|
| Test | Flag | Default | Description |
|
|
|------|------|---------|-------------|
|
|
| `agc-linearity` | `--freq` | 1200 | Test frequency in MHz |
|
|
| `band-flatness` | `--start` | 950 | Start frequency in MHz |
|
|
| `band-flatness` | `--stop` | 1500 | Stop frequency in MHz |
|
|
| `band-flatness` | `--step` | 10 | Frequency step in MHz |
|
|
| `freq-accuracy` | `--freqs` | 1000,1100,1200,1300,1400 | Comma-separated test frequencies |
|
|
| `mds` | `--freq` | 1200 | Test frequency in MHz |
|
|
| `bpsk-probe` | `--freq` | 1200 | Test frequency in MHz |
|
|
|
|
## CSV Output Format
|
|
|
|
All tests write the same CSV format when `--output` is specified:
|
|
|
|
| Column | Description |
|
|
|--------|-------------|
|
|
| `timestamp` | ISO 8601 UTC timestamp |
|
|
| `test_name` | Test identifier (agc_linearity, band_flatness, freq_accuracy, mds, bpsk_probe) |
|
|
| `freq_mhz` | Frequency in MHz |
|
|
| `atten_db` | HMC472A attenuation setting in dB |
|
|
| `agc1` | BCM3440 AGC1 register value |
|
|
| `agc2` | BCM3440 AGC2 register value |
|
|
| `power_db` | Derived power estimate in dB (relative) |
|
|
| `snr_raw` | Raw SNR register value |
|
|
| `snr_db` | SNR in dB |
|
|
| `locked` | Demodulator lock status |
|
|
| `lock_raw` | Raw lock status byte |
|
|
| `status` | Status byte |
|
|
| `notes` | Test-specific metadata |
|
|
|
|
## Interpreting Results
|
|
|
|
### AGC Linearity Curves
|
|
|
|
A well-behaved AGC should show a roughly linear relationship between attenuation (dB) and AGC
|
|
register value. Look for:
|
|
|
|
- **Linear region**: Where AGC tracks input power changes 1:1 in dB — this is the useful
|
|
measurement range
|
|
- **Saturation**: Where adding more signal doesn't change AGC — the tuner's front end is
|
|
compressing
|
|
- **Noise floor**: Where reducing signal doesn't change AGC — the receiver's internal noise
|
|
dominates
|
|
|
|
### Band Flatness
|
|
|
|
Ideal response is flat across the band. In practice:
|
|
- **1-3 dB variation** across 950-1500 MHz is typical for a consumer-grade tuner
|
|
- **Sharp dips** may indicate cable resonances or connector issues
|
|
- **Systematic slope** (gain increasing or decreasing with frequency) is common and can be
|
|
corrected in post-processing
|
|
|
|
### Frequency Error
|
|
|
|
Consumer satellite tuners typically have **50-200 kHz frequency accuracy**. A consistent offset
|
|
suggests LO error in the BCM3440. Frequency-dependent error suggests tuning nonlinearity.
|
|
|
|
## Mock Mode
|
|
|
|
Run with `SKYWALKER_MOCK=1` for testing without hardware:
|
|
|
|
```bash
|
|
SKYWALKER_MOCK=1 python tools/rf_testbench.py agc-linearity --freq 1200 --nanovna manual
|
|
```
|
|
|
|
Mock mode uses built-in simulated responses for the SkyWalker-1 and HMC472A. The NanoVNA prompts
|
|
are skipped. Useful for verifying command structure and CSV output format.
|
|
|
|
## See Also
|
|
|
|
- [Spectrum Analysis](/tools/spectrum-analysis/) — frequency sweep techniques
|
|
- [Hydrogen 21 cm](/tools/h21cm/) — direct L-band input mode (same RF path concept)
|
|
- [Signal Monitoring](/bcm4500/signal-monitoring/) — AGC and SNR register details
|
|
- [HMC472A Documentation](https://hmc472.l.zmesh.systems/) — attenuator module reference
|
|
- [Applications & Use Cases](/guides/applications/) — RF test and measurement context
|