diff --git a/astro.config.mjs b/astro.config.mjs
index ce33e5b..a4d2773 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -32,6 +32,7 @@ export default defineConfig({
{ label: 'Overview', slug: 'mcnanovna/overview' },
{ label: 'Tool Reference', slug: 'mcnanovna/tools' },
{ label: 'Prompts', slug: 'mcnanovna/prompts' },
+ { label: 'Multi-VNA Coordination', slug: 'mcnanovna/multi-vna' },
{ label: 'Web UI', slug: 'mcnanovna/webui' },
],
},
@@ -49,6 +50,8 @@ export default defineConfig({
{ label: 'Positioner Build', slug: 'hardware/positioner-build' },
{ label: 'Wiring Diagram', slug: 'hardware/wiring' },
{ label: 'Firmware', slug: 'hardware/firmware' },
+ { label: 'VNA Trigger Wiring', slug: 'hardware/trigger-wiring' },
+ { label: 'VNA External Clock', slug: 'hardware/external-clock' },
],
},
{
@@ -57,6 +60,7 @@ export default defineConfig({
{ label: '3D Pattern Measurement', slug: 'tutorials/pattern-measurement' },
{ label: 'VNA Calibration', slug: 'tutorials/calibration' },
{ label: 'Antenna Analysis', slug: 'tutorials/antenna-analysis' },
+ { label: 'Multi-VNA Basics', slug: 'tutorials/multi-vna-basics' },
],
},
{
diff --git a/src/content/docs/getting-started/quickstart.mdx b/src/content/docs/getting-started/quickstart.mdx
index 4e9cef3..60bfb47 100644
--- a/src/content/docs/getting-started/quickstart.mdx
+++ b/src/content/docs/getting-started/quickstart.mdx
@@ -49,7 +49,8 @@ You should see device details like firmware version, serial number, and frequenc
- [Install mcpositioner](/mcpositioner/overview/) for automated antenna measurements
- [Run a calibration](/tutorials/calibration/) for accurate measurements
-- [Explore all 78 tools](/mcnanovna/tools/)
+- [Explore all 91 tools](/mcnanovna/tools/)
+- [Multi-VNA measurements](/tutorials/multi-vna-basics/) — Use two VNAs together
## Troubleshooting
diff --git a/src/content/docs/hardware/external-clock.mdx b/src/content/docs/hardware/external-clock.mdx
new file mode 100644
index 0000000..19c3e04
--- /dev/null
+++ b/src/content/docs/hardware/external-clock.mdx
@@ -0,0 +1,264 @@
+---
+title: VNA External Clock Modification
+description: Share a clock reference for Tier 3 phase-coherent measurements
+---
+
+import { Steps, Tabs, TabItem, Aside, Card, CardGrid } from '@astrojs/starlight/components';
+
+Phase-coherent operation (Tier 3) locks all VNAs to a shared 26 MHz reference clock, achieving ±1° phase alignment. This is essential for antenna arrays, MIMO testing, and any measurement where relative phase matters.
+
+
+
+## Prerequisites
+
+Complete [hardware trigger wiring (Tier 2)](/hardware/trigger-wiring/) first. Phase coherent operation requires both:
+
+1. Shared clock reference (this modification)
+2. Hardware trigger synchronization (Tier 2)
+
+## When You Need This
+
+
+
+ Phased arrays require known phase relationships between elements. Software or trigger sync alone can't provide phase information.
+
+
+ Multiple-input-multiple-output antenna characterization needs coherent phase measurement across all paths.
+
+
+ Comparing oscillator phase noise requires a more stable reference than the internal crystal.
+
+
+ Verify beam patterns and null depths on multi-element antennas.
+
+
+
+## Clock Reference Options
+
+| Source | Stability | Cost | Best For |
+|--------|-----------|------|----------|
+| **OCXO** (oven crystal) | ~1 ppb | $50-200 | Bench work, highest stability |
+| **TCXO** | ~1 ppm | $10-30 | Portable, adequate for most |
+| **GPS-DO** (GPS disciplined) | ~0.01 ppb | $100-300 | Absolute accuracy, traceable |
+| **Single VNA CLK2** | Device-dependent | $0 | Quick hack, tap one VNA's Si5351 |
+
+
+
+## Parts Needed
+
+- 26 MHz reference oscillator (OCXO, TCXO, or GPS-DO module)
+- Clock distribution splitter (for 3+ VNAs)
+- 100nF DC blocking capacitors (0402 or 0603)
+- SMA connectors and coax
+- Fine soldering equipment (hot air recommended)
+
+## Modification Steps
+
+
+1. **Open the enclosure**
+
+ Remove the four screws and carefully separate the front panel from the PCB. Note the ribbon cable to the LCD.
+
+2. **Locate the Si5351**
+
+ The Si5351 clock generator IC is typically near the MCU. It's a small QFN package marked "Si5351A" or similar.
+
+ ```
+ ┌──────────────────────────────────────┐
+ │ │
+ │ ┌─────┐ │
+ │ │Si5351│◄── Clock generator │
+ │ └─────┘ │
+ │ │ │
+ │ [Y1]◄── 26 MHz crystal │
+ │ │
+ └──────────────────────────────────────┘
+ ```
+
+3. **Cut the crystal trace**
+
+ The Si5351 CLKIN pin (pin 1) connects to the on-board 26 MHz crystal. Cut this trace to disconnect the internal crystal:
+
+ - Use a sharp blade or micro drill
+ - Cut between the crystal and pin 1
+ - Verify with multimeter (no continuity)
+
+
+
+4. **Add DC blocking capacitor**
+
+ Solder a 100nF capacitor in series with the external clock input:
+
+ ```
+ External ┌───┐
+ Clock ─────►│100n├────► Si5351 CLKIN (pin 1)
+ └───┘
+ ```
+
+ This blocks any DC offset from your reference source.
+
+5. **Add external clock connection**
+
+ Options for bringing the clock signal in:
+
+ - **SMA connector**: Drill the enclosure, mount an SMA
+ - **Wire**: Run a thin coax through an existing opening
+ - **Test point**: Solder to an accessible pad
+
+ Keep the clock path short (< 5cm) to minimize pickup.
+
+6. **Reassemble and test**
+
+ - Reconnect the LCD ribbon cable
+ - Reassemble enclosure
+ - Apply external 26 MHz reference
+ - Verify VNA powers up and runs
+
+
+
+## Clock Distribution
+
+For multiple VNAs, distribute the reference clock:
+
+```
+ ┌──────────────────────┐
+ │ 26 MHz Reference │
+ │ (OCXO or GPS-DO) │
+ └──────────┬───────────┘
+ │
+ ┌────────────────┼────────────────┐
+ │ │ │
+ ┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
+ │ VNA #1 │ │ VNA #2 │ │ VNA #N │
+ │ (Leader) │ │(Follower) │ │(Follower) │
+ │ │ │ │ │ │
+ │ CLK_IN ←──│────│── CLK ────│────│── CLK │
+ │ TRIG_OUT ─│────│→ TRIG_IN │ │→ TRIG_IN │
+ └───────────┘ └───────────┘ └───────────┘
+```
+
+### Distribution options
+
+| Method | VNAs | Notes |
+|--------|------|-------|
+| **Direct** | 2 | Split with 50Ω resistors |
+| **Clock buffer IC** | 2-8 | LMK00101, CDCE913, etc. |
+| **RF splitter** | Any | Power divider, adds insertion loss |
+
+**Important**: Use equal-length cables to all VNAs for matched phase.
+
+## Firmware Commands
+
+Custom firmware adds these clock commands:
+
+| Command | Description |
+|---------|-------------|
+| `clk_ref {internal\|external}` | Select clock source |
+| `clk_status` | PLL lock status, phase offset |
+
+### Switching to external clock
+
+```
+raw_command(command="clk_ref external")
+```
+
+The Si5351 PLLs need ~100ms to lock after switching. Check lock status:
+
+```
+raw_command(command="clk_status")
+# Output: locked=true, source=external
+```
+
+## Using phase_coherent_sweep
+
+Once all VNAs have external clock and trigger wiring:
+
+Say: "Run a phase-coherent sweep on all devices from 430 to 440 MHz"
+
+The assistant calls:
+
+```
+phase_coherent_sweep(
+ device_ids=["0001234567", "0009876543", "0005555555"],
+ start_hz=430000000,
+ stop_hz=440000000,
+ points=101
+)
+```
+
+This automatically:
+
+1. Switches all devices to external clock
+2. Waits for PLL lock (~100ms)
+3. Configures trigger (leader + followers)
+4. Runs hardware-synced sweep
+5. Restores internal clock
+
+## Validation
+
+After completing the modification, verify phase coherence:
+
+
+1. **Connect a known reference**
+
+ Use a power splitter to feed the same signal to S11 on all VNAs.
+
+2. **Measure phase**
+
+ Compare S11 phase readings across VNAs at the same frequency. With phase coherence, they should match within ±1°.
+
+3. **Sweep and compare**
+
+ Run multiple sweeps. Phase should be stable across sweeps—if it drifts, check clock distribution.
+
+
+
+## Troubleshooting
+
+### PLL won't lock
+
+1. Verify 26 MHz signal at CLKIN (oscilloscope)
+2. Check signal level: Si5351 expects 0.6-1.6 Vpp
+3. Ensure DC blocking cap is present and not shorted
+4. Try different clock source
+
+### Phase drifts over time
+
+1. Allow OCXO to warm up (15-30 minutes)
+2. Check cable connections for intermittent contact
+3. Verify clock splitter isn't introducing phase shift
+4. Avoid temperature changes during measurement
+
+### VNA won't start without external clock
+
+1. Reconnect internal crystal (unsolder cut)
+2. Use a backup clock source
+3. Consider adding a switch for internal/external
+
+### Phase varies with frequency
+
+1. Expected: cables have frequency-dependent phase shift
+2. Use matched-length clock distribution cables
+3. Calibrate VNAs at each frequency band
+
+## Specifications
+
+| Parameter | Value |
+|-----------|-------|
+| Reference frequency | 26 MHz (must match Si5351 XTAL spec) |
+| Input level | 0.6-1.6 Vpp into CLKIN |
+| PLL lock time | ~100 ms |
+| Phase accuracy | ±1° at 1 GHz |
+| Jitter contribution | < 1 ps RMS (typical) |
+
+## Next Steps
+
+- [Multi-VNA Coordination](/mcnanovna/multi-vna/) — Understand all three tiers
+- [Hardware Trigger Wiring](/hardware/trigger-wiring/) — Required for Tier 3
+- [Tool Reference](/mcnanovna/tools/) — Phase coherent tools
diff --git a/src/content/docs/hardware/trigger-wiring.mdx b/src/content/docs/hardware/trigger-wiring.mdx
new file mode 100644
index 0000000..a641e3d
--- /dev/null
+++ b/src/content/docs/hardware/trigger-wiring.mdx
@@ -0,0 +1,232 @@
+---
+title: VNA Hardware Trigger Wiring
+description: Wire multiple NanoVNAs for Tier 2 synchronized measurements
+---
+
+import { Steps, Tabs, TabItem, Aside } from '@astrojs/starlight/components';
+
+Hardware trigger synchronization (Tier 2) achieves ±10-50µs timing between VNAs—100x tighter than software coordination. This guide shows you how to wire the trigger lines between devices.
+
+## When You Need This
+
+| Use Case | Tier 1 (Software) | Tier 2 (Hardware Trigger) |
+|----------|-------------------|---------------------------|
+| Antenna comparison | ✓ | ✓ |
+| SWR/impedance | ✓ | ✓ |
+| Signal level measurements | ✓ | ✓ |
+| Transmission path timing | Limited | ✓ |
+| Differential S21 | Limited | ✓ |
+| Multi-VNA transfer functions | ✗ | ✓ |
+
+For phase-aligned measurements, you'll also need [external clock (Tier 3)](/hardware/external-clock/).
+
+## Parts Needed
+
+- Jumper wires (Dupont or similar)
+- Soldering iron and solder (fine tip recommended)
+- NanoVNA-H with custom firmware supporting trigger commands
+
+
+
+## Pin Locations
+
+The trigger system uses two GPIO pins on the STM32F303:
+
+| Pin | Function | Location | Description |
+|-----|----------|----------|-------------|
+| **PA0** | TRIG_IN | See board diagram | External trigger input (rising edge) |
+| **PB14** | TRIG_OUT | See board diagram | Pulse output at sweep start |
+
+### NanoVNA-H Rev 3.4 Board
+
+```
+┌─────────────────────────────────────────┐
+│ │
+│ ┌───────────────────────┐ │
+│ │ │ │
+│ │ LCD │ │
+│ │ │ │
+│ └───────────────────────┘ │
+│ │
+│ │
+│ [PA0]● ●[PB14] │
+│ TRIG_IN TRIG_OUT │
+│ │
+│ ┌──┐ ┌──┐ │
+│ │P1│ │P2│ │
+│ └──┘ └──┘ │
+│ Port 1 Port 2 │
+└─────────────────────────────────────────┘
+```
+
+
+
+## Wiring Steps
+
+
+1. **Identify the leader VNA**
+
+ Choose one VNA as the "leader"—it will generate the trigger pulse that starts all sweeps. The others are "followers."
+
+2. **Solder wires to pins**
+
+ On the **leader VNA**:
+ - Solder a wire to **PB14** (TRIG_OUT)
+
+ On each **follower VNA**:
+ - Solder a wire to **PA0** (TRIG_IN)
+
+ Use thin wire (30 AWG or similar) to avoid stressing the pads.
+
+3. **Connect the trigger bus**
+
+ Wire all followers' TRIG_IN lines to the leader's TRIG_OUT:
+
+ ```
+ Leader VNA Follower VNA #1
+ ┌─────────┐ ┌─────────┐
+ │ PB14 │──────────────────│ PA0 │
+ │(TRIG_OUT)│ │(TRIG_IN) │
+ └─────────┘ │ └─────────┘
+ │
+ │ Follower VNA #2
+ │ ┌─────────┐
+ └────────│ PA0 │
+ │(TRIG_IN) │
+ └─────────┘
+ ```
+
+ For more than 2 followers, daisy-chain or use a splitter.
+
+4. **Verify ground reference**
+
+ All VNAs share ground via USB (same host computer). No additional ground wire needed.
+
+ If using VNAs on different computers, add a common ground wire.
+
+5. **Test trigger signaling**
+
+ Use a multimeter or oscilloscope to verify:
+ - PB14 can be toggled (use `raw_command("trig_out pulse")`)
+ - PA0 sees the pulse on followers
+
+
+
+## Firmware Requirements
+
+Stock NanoVNA firmware doesn't include trigger commands. You need custom firmware with:
+
+| Command | Description |
+|---------|-------------|
+| `trig_mode {software\|hardware\|leader\|follower}` | Set trigger mode |
+| `trig_out {on\|off\|pulse}` | Manual trigger control |
+| `trig_status` | Read trigger state |
+
+Check capability with `detect_capabilities()`:
+
+```json
+{
+ "device_id": "0001234567",
+ "capabilities": {
+ "hardware_trigger": true,
+ "external_clock": false
+ },
+ "tier": 2
+}
+```
+
+
+
+## Using hardware_sync_sweep
+
+Once wiring is complete and firmware supports triggers:
+
+Say: "Run a hardware-synced sweep from 144 to 148 MHz with device 0001234567 as leader"
+
+The assistant calls:
+
+```
+hardware_sync_sweep(
+ leader_device_id="0001234567",
+ follower_device_ids=["0009876543"],
+ start_hz=144000000,
+ stop_hz=148000000,
+ points=101
+)
+```
+
+This automatically:
+
+1. Sets leader to "leader" mode
+2. Sets followers to "follower" mode
+3. Runs parallel scans (hardware synchronized)
+4. Restores "software" mode
+
+## Testing the Trigger Line
+
+### Manual test via raw_command
+
+```
+# On leader - generate pulse
+raw_command(device_id="0001234567", command="trig_out pulse")
+
+# On follower - check status
+raw_command(device_id="0009876543", command="trig_status")
+```
+
+Expected output: `trigger_count` should increment.
+
+### Oscilloscope verification
+
+- Pulse width: ~10µs
+- Rising edge: < 1µs
+- Voltage: 3.3V logic level
+
+## Troubleshooting
+
+### Trigger not detected
+
+1. Verify wiring continuity with multimeter
+2. Check firmware has `trig_mode` command: `raw_command("help")`
+3. Ensure ground is shared between VNAs
+4. Try shorter trigger wire (< 30cm recommended)
+
+### Erratic triggering
+
+1. Add 100Ω series resistor on TRIG_OUT to reduce ringing
+2. Keep trigger wire away from RF paths
+3. Use shielded wire for long runs (> 30cm)
+4. Check for EMI from nearby equipment
+
+### Sweeps still not synchronized
+
+1. Verify both VNAs have same sweep settings (start, stop, points)
+2. Check trigger mode is correctly set before sweep
+3. Ensure leader starts sweep before followers timeout
+
+### Capability shows false
+
+1. Firmware may not support triggers
+2. Flash custom firmware with trigger support
+3. Run `detect_capabilities()` after firmware update
+
+## Electrical Specifications
+
+| Parameter | Value |
+|-----------|-------|
+| TRIG_OUT pulse width | 10µs |
+| TRIG_IN threshold | 1.6V (TTL-compatible) |
+| Maximum trigger cable length | 1m (unshielded), 5m (shielded) |
+| Edge-to-sweep latency | < 50µs |
+
+## Next Steps
+
+- [External Clock Modification](/hardware/external-clock/) — Add Tier 3 phase coherence
+- [Multi-VNA Coordination](/mcnanovna/multi-vna/) — Understand all synchronization tiers
+- [Tool Reference](/mcnanovna/tools/) — Hardware trigger tools
diff --git a/src/content/docs/mcnanovna/multi-vna.mdx b/src/content/docs/mcnanovna/multi-vna.mdx
new file mode 100644
index 0000000..634680b
--- /dev/null
+++ b/src/content/docs/mcnanovna/multi-vna.mdx
@@ -0,0 +1,321 @@
+---
+title: Multi-VNA Coordination
+description: Synchronized measurements across multiple NanoVNA devices
+---
+
+import { Tabs, TabItem, Aside, Card, CardGrid } from '@astrojs/starlight/components';
+
+mcnanovna can control multiple NanoVNA devices simultaneously, enabling measurements that a single 2-port VNA can't perform. This page explains the three synchronization tiers and when to use each.
+
+## Why Multiple VNAs?
+
+A single NanoVNA provides 2 ports—enough for S11 (reflection) and S21 (transmission) through one device. Multiple VNAs expand your measurement capability:
+
+| VNAs | Ports | Enables |
+|------|-------|---------|
+| 1 | 2 | S11, S21 (standard) |
+| 2 | 4 | True 4-port, A/B comparison, long path loss |
+| 3+ | 2N | Phased arrays, MIMO, multi-element antennas |
+
+## The Synchronization Challenge
+
+When measuring across multiple VNAs, timing matters:
+
+- **Amplitude comparison**: ±5ms is fine—signal levels don't change that fast
+- **Time-aligned capture**: Need ±10-50µs for transfer functions
+- **Phase alignment**: Need shared clock for coherent phase
+
+mcnanovna provides three tiers to match your precision needs.
+
+## The Three Tiers
+
+
+
+ **±2-5ms timing**
+
+ Parallel async execution via software. Works with any firmware, no modifications needed.
+
+ Best for: Antenna comparison, SWR checks, signal level surveys
+
+
+ **±10-50µs timing**
+
+ One VNA triggers the others via GPIO. Requires custom firmware and trigger wiring.
+
+ Best for: Transfer functions, differential S21, timing-sensitive measurements
+
+
+ **±1° phase alignment**
+
+ All VNAs share a 26 MHz clock reference plus hardware trigger.
+
+ Best for: Antenna arrays, MIMO, beamforming, phase noise comparison
+
+
+
+## Tier Details
+
+
+
+ ### How It Works
+
+ mcnanovna sends scan commands to all VNAs in parallel using Python's `asyncio`. The timing depends on USB latency and OS scheduling.
+
+ ### Requirements
+
+ - Multiple VNAs connected via USB
+ - Stock firmware (any version)
+ - No hardware modifications
+
+ ### Limitations
+
+ - ±2-5ms timing (good enough for most amplitude measurements)
+ - No phase relationship between devices
+ - USB contention can add jitter
+
+ ### Tools
+
+ | Tool | Description |
+ |------|-------------|
+ | `sync_sweep` | Parallel sweep across devices |
+ | `multi_antenna_compare` | Compare S11 metrics |
+ | `differential_s21` | Two-VNA transmission |
+
+ ### Example
+
+ ```
+ sync_sweep(
+ device_ids=["0001234567", "0009876543"],
+ start_hz=144000000,
+ stop_hz=148000000,
+ points=101
+ )
+ ```
+
+
+
+ ### How It Works
+
+ One VNA (leader) pulses a GPIO at sweep start. Other VNAs (followers) wait for this trigger before beginning their sweep.
+
+ ### Requirements
+
+ - Custom firmware with trigger commands (`trig_mode`, `trig_out`)
+ - Physical trigger wire from leader TRIG_OUT to follower TRIG_IN
+ - See [Hardware Trigger Wiring](/hardware/trigger-wiring/)
+
+ ### Limitations
+
+ - ±10-50µs timing (excellent for amplitude)
+ - Still no phase coherence (each VNA has its own clock)
+ - Requires soldering and firmware changes
+
+ ### Tools
+
+ | Tool | Description |
+ |------|-------------|
+ | `set_trigger_mode` | Configure leader/follower |
+ | `hardware_sync_sweep` | Hardware-triggered sweep |
+
+ ### Example
+
+ ```
+ hardware_sync_sweep(
+ leader_device_id="0001234567",
+ follower_device_ids=["0009876543"],
+ start_hz=144000000,
+ stop_hz=148000000,
+ points=101
+ )
+ ```
+
+
+
+ ### How It Works
+
+ All VNAs receive the same 26 MHz reference clock from an external source (OCXO, GPS-DO). Combined with hardware trigger, sweeps are phase-aligned.
+
+ ### Requirements
+
+ - Tier 2 prerequisites (trigger wiring + firmware)
+ - External 26 MHz reference oscillator
+ - PCB modification to inject clock at Si5351
+ - See [External Clock Modification](/hardware/external-clock/)
+
+ ### Limitations
+
+ - Requires invasive hardware modification
+ - More expensive (reference oscillator)
+ - Voids warranty
+ - Overkill for most measurements
+
+ ### Tools
+
+ | Tool | Description |
+ |------|-------------|
+ | `set_clock_reference` | Switch internal/external |
+ | `phase_coherent_sweep` | Phase-aligned sweep |
+
+ ### Example
+
+ ```
+ phase_coherent_sweep(
+ device_ids=["0001234567", "0009876543", "0005555555"],
+ start_hz=430000000,
+ stop_hz=440000000,
+ points=101
+ )
+ ```
+
+
+
+## Smart Tier Selection
+
+Don't want to think about tiers? Use `coordinated_sweep`:
+
+```
+coordinated_sweep(
+ start_hz=144000000,
+ stop_hz=148000000,
+ points=101
+)
+```
+
+It automatically selects the best method based on detected capabilities:
+
+```
+ ┌─────────────────────┐
+ │ coordinated_sweep() │
+ └──────────┬──────────┘
+ │
+ ┌───────────────┼───────────────┐
+ │ │ │
+ ▼ │ ▼
+ ┌─────────────────┐ │ ┌─────────────────┐
+ │ All have │ │ │ All have │
+ │ external_clock? │───Yes──┘ │ hardware_trigger?│
+ └────────┬────────┘ │ └────────┬────────┘
+ │No │ │Yes
+ └────────────┐ │ ┌────────┘
+ ▼ ▼ ▼
+ ┌─────────────────┐
+ │ Use Tier 3 │
+ │ phase_coherent │
+ └─────────────────┘
+ │No
+ ▼
+ ┌─────────────────┐
+ │ Use Tier 2 │
+ │hardware_trigger │
+ └─────────────────┘
+ │No
+ ▼
+ ┌─────────────────┐
+ │ Use Tier 1 │
+ │ software │
+ └─────────────────┘
+```
+
+## Device Management
+
+### Discovery
+
+```
+list_devices()
+```
+
+Returns all connected VNAs with their capabilities:
+
+```json
+{
+ "devices": [
+ {
+ "device_id": "0001234567",
+ "port": "/dev/ttyACM0",
+ "board": "NanoVNA-H4",
+ "connected": true,
+ "capabilities": {
+ "hardware_trigger": true,
+ "external_clock": false
+ }
+ }
+ ],
+ "default": "0001234567"
+}
+```
+
+### Targeting
+
+**Default device**: When one VNA is connected, it's automatically the default. With multiple, set one:
+
+```
+set_default_device(device_id="0001234567")
+```
+
+**Explicit targeting**: Override default with `device_id` on any tool:
+
+```
+scan(device_id="0009876543", start_hz=144e6, stop_hz=148e6)
+```
+
+### Hot-plug Detection
+
+After connecting/disconnecting VNAs:
+
+```
+refresh_devices()
+```
+
+## Common Workflows
+
+### A/B Antenna Comparison
+
+Connect two antennas to two VNAs, then:
+
+```
+multi_antenna_compare(
+ device_ids=["antenna_a_vna", "antenna_b_vna"],
+ start_hz=144000000,
+ stop_hz=148000000
+)
+```
+
+Returns:
+
+| Metric | Antenna A | Antenna B |
+|--------|-----------|-----------|
+| Min SWR | 1.15 | 1.32 |
+| Resonance | 145.2 MHz | 144.8 MHz |
+| Bandwidth | 4.1 MHz | 3.2 MHz |
+
+### Long Cable Path Loss
+
+Measure a cable too long to keep both ends near one VNA:
+
+```
+differential_s21(
+ source_device_id="near_end_vna",
+ receiver_device_id="far_end_vna",
+ start_hz=1000000,
+ stop_hz=500000000
+)
+```
+
+The source VNA outputs CW while the receiver measures. Returns S21 magnitude at each frequency.
+
+## Guided Prompts
+
+mcnanovna includes prompts for multi-VNA workflows:
+
+| Prompt | Description |
+|--------|-------------|
+| `multi_device_setup` | Initial device discovery and configuration |
+| `hardware_trigger_setup` | Tier 2 wiring and testing guide |
+| `phase_coherent_setup` | Tier 3 clock reference setup |
+
+## See Also
+
+- [Multi-VNA Tutorial](/tutorials/multi-vna-basics/) — Hands-on first multi-VNA measurement
+- [Hardware Trigger Wiring](/hardware/trigger-wiring/) — Tier 2 physical setup
+- [External Clock Modification](/hardware/external-clock/) — Tier 3 clock distribution
+- [Tool Reference](/mcnanovna/tools/) — All coordination tools
diff --git a/src/content/docs/mcnanovna/overview.mdx b/src/content/docs/mcnanovna/overview.mdx
index 1295484..121e0c2 100644
--- a/src/content/docs/mcnanovna/overview.mdx
+++ b/src/content/docs/mcnanovna/overview.mdx
@@ -5,7 +5,7 @@ description: MCP server for NanoVNA-H vector network analyzers
import { Aside } from '@astrojs/starlight/components';
-mcnanovna gives LLMs direct control of NanoVNA-H vector network analyzers over USB serial. It exposes 78 MCP tools for frequency sweeps, S-parameter measurements, calibration, LCD capture, RF analysis, and 3D antenna radiation pattern visualization.
+mcnanovna gives LLMs direct control of NanoVNA-H vector network analyzers over USB serial. It exposes 91 MCP tools for frequency sweeps, S-parameter measurements, calibration, LCD capture, RF analysis, 3D antenna radiation pattern visualization, and multi-VNA coordination.
## Capabilities
@@ -34,6 +34,20 @@ mcnanovna gives LLMs direct control of NanoVNA-H vector network analyzers over U
- Pattern import from CSV, EMCAR, NEC2, Touchstone S1P
- Optional Three.js web viewer
+### Multi-VNA Coordination
+- Control multiple NanoVNA devices simultaneously
+- Three synchronization tiers with increasing precision
+- Device targeting via optional `device_id` parameter on all tools
+- Automatic sync method selection with `coordinated_sweep`
+
+| Tier | Method | Precision | Requirements |
+|------|--------|-----------|--------------|
+| 1 | Software | ±2-5ms | None (stock firmware) |
+| 2 | Hardware Trigger | ±10-50µs | Custom firmware + trigger wire |
+| 3 | Phase Coherent | ±1° | External clock + Tier 2 |
+
+See [Multi-VNA Coordination](/mcnanovna/multi-vna/) for detailed tier comparison and workflow guides.
+
## Supported Hardware
| Device | Frequency Range | Notes |
@@ -57,21 +71,23 @@ Other NanoVNA variants using the same USB serial protocol (VID 0x0483, PID 0x574
│ │ mcnanovna server │ │
│ │ ┌─────────┐ ┌────────────┐ ┌─────────────┐ │ │
│ │ │ tools/ │ │ protocol.py│ │calculations │ │ │
-│ │ │ 8 mixins│ │ USB serial│ │ S-param │ │ │
+│ │ │ 9 mixins│ │ USB serial│ │ S-param │ │ │
│ │ └────┬────┘ └─────┬──────┘ │ math │ │ │
│ │ │ │ └─────────────┘ │ │
│ │ ▼ ▼ │ │
│ │ ┌──────────────────────────────────────────┐ │ │
-│ │ │ NanoVNA class │ │ │
-│ │ │ (connection lifecycle, auto-reconnect) │ │ │
+│ │ │ DeviceRegistry (multi-VNA) │ │ │
+│ │ │ ┌────────────┐ ┌────────────┐ │ │ │
+│ │ │ │ NanoVNA #1 │ ... │ NanoVNA #N │ │ │ │
+│ │ │ └────────────┘ └────────────┘ │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ USB Serial │
│ ▼ │
-│ ┌──────────────────┐ │
-│ │ NanoVNA-H │ │
-│ └──────────────────┘ │
+│ ┌──────────────┐ ┌──────────────┐ │
+│ │ NanoVNA-H #1 │...│ NanoVNA-H #N │ │
+│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
```
diff --git a/src/content/docs/mcnanovna/tools.mdx b/src/content/docs/mcnanovna/tools.mdx
index 553d5ab..75dab1b 100644
--- a/src/content/docs/mcnanovna/tools.mdx
+++ b/src/content/docs/mcnanovna/tools.mdx
@@ -1,9 +1,9 @@
---
title: Tool Reference
-description: All 78 mcnanovna MCP tools
+description: All 91 mcnanovna MCP tools
---
-import { Tabs, TabItem } from '@astrojs/starlight/components';
+import { Tabs, TabItem, Aside } from '@astrojs/starlight/components';
## Measurement Tools
@@ -123,6 +123,56 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
| `import_pattern_s1p` | Import from Touchstone S1P |
| `list_pattern_formats` | List supported import formats |
+## Coordination Tools
+
+Manage and synchronize multiple NanoVNA devices simultaneously.
+
+### Device Management
+
+| Tool | Description |
+|------|-------------|
+| `list_devices` | List all connected VNAs with status and capabilities |
+| `refresh_devices` | Re-scan USB ports for hot-plugged devices |
+| `set_default_device` | Set default VNA for subsequent calls |
+| `clear_default_device` | Clear default, require explicit device_id |
+| `detect_capabilities` | Check hardware trigger and clock support |
+
+### Tier 1: Software Synchronization
+
+| Tool | Description |
+|------|-------------|
+| `sync_sweep` | Software-coordinated parallel sweep (±2-5ms) |
+| `multi_antenna_compare` | Compare S11 across multiple antennas |
+| `differential_s21` | Two-VNA transmission measurement |
+
+### Tier 2: Hardware Trigger
+
+Requires custom firmware and physical trigger wiring. See [VNA Trigger Wiring](/hardware/trigger-wiring/) for hardware setup.
+
+| Tool | Description |
+|------|-------------|
+| `set_trigger_mode` | Configure hardware trigger mode |
+| `hardware_sync_sweep` | Hardware-triggered sync sweep (±10-50µs) |
+
+### Tier 3: Phase Coherent
+
+Requires external 26 MHz clock reference plus Tier 2. See [VNA External Clock](/hardware/external-clock/) for hardware modification guide.
+
+| Tool | Description |
+|------|-------------|
+| `set_clock_reference` | Set internal/external clock reference |
+| `phase_coherent_sweep` | Phase-coherent sweep with shared clock (±1°) |
+
+### Smart Coordination
+
+| Tool | Description |
+|------|-------------|
+| `coordinated_sweep` | Auto-selects best available sync method |
+
+
+
## Example Usage
@@ -156,4 +206,20 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
Calls: save(0)
```
+
+ ```
+ User: Compare my two 2m antennas simultaneously
+
+ Calls: list_devices()
+ # Returns: [{id: "0001234567", ...}, {id: "0007654321", ...}]
+
+ Calls: sync_sweep(
+ device_ids=["0001234567", "0007654321"],
+ start_hz=144000000,
+ stop_hz=148000000,
+ points=101
+ )
+ Calls: multi_antenna_compare()
+ ```
+
diff --git a/src/content/docs/tutorials/multi-vna-basics.mdx b/src/content/docs/tutorials/multi-vna-basics.mdx
new file mode 100644
index 0000000..1c3ad2e
--- /dev/null
+++ b/src/content/docs/tutorials/multi-vna-basics.mdx
@@ -0,0 +1,222 @@
+---
+title: Your First Multi-VNA Measurement
+description: Compare antennas using two NanoVNAs simultaneously
+---
+
+import { Steps, Tabs, TabItem, Aside } from '@astrojs/starlight/components';
+
+In this tutorial, you'll use two NanoVNA devices together to measure and compare two antennas side-by-side. By the end, you'll understand device discovery, targeting, and software-synchronized sweeps.
+
+## What You'll Learn
+
+- Discover all connected VNAs
+- Target specific devices
+- Run synchronized sweeps
+- Compare antenna performance
+
+## Prerequisites
+
+- Two NanoVNA-H devices connected via USB
+- Two antennas to compare (or one antenna with two feedlines)
+- mcnanovna MCP server installed
+
+
+
+## Discover Your Devices
+
+
+1. **Connect both VNAs**
+
+ Plug both NanoVNA devices into USB ports. Each needs its own port.
+
+2. **List devices**
+
+ Say: "List all connected NanoVNA devices"
+
+ The assistant calls `list_devices()` and returns something like:
+
+ ```json
+ {
+ "devices": [
+ {"device_id": "0001234567", "port": "/dev/ttyACM0", "board": "NanoVNA-H4"},
+ {"device_id": "0009876543", "port": "/dev/ttyACM1", "board": "NanoVNA-H"}
+ ],
+ "default": "0001234567",
+ "count": 2
+ }
+ ```
+
+3. **Note the device IDs**
+
+ Each VNA has a unique `device_id` (its serial number or port path). Write these down:
+
+ | Device ID | Connected Antenna |
+ |-----------|-------------------|
+ | 0001234567 | Antenna A |
+ | 0009876543 | Antenna B |
+
+
+
+## Set Up Device Targeting
+
+With multiple VNAs, you have two options for targeting:
+
+### Option 1: Set a Default
+
+If you'll mostly use one VNA:
+
+Say: "Set device 0001234567 as the default"
+
+Now all single-device tools (scan, analyze, etc.) will target that VNA unless you specify otherwise.
+
+### Option 2: Specify Each Time
+
+Add `device_id` to any tool call:
+
+Say: "Scan from 144 to 148 MHz on device 0009876543"
+
+
+
+## Calibrate Each VNA
+
+
+1. **Calibrate the first VNA**
+
+ Say: "Calibrate device 0001234567 for 144 to 148 MHz"
+
+ Follow the SOLT calibration steps: load, open, short, through.
+
+ Say: "Save calibration to slot 1"
+
+2. **Calibrate the second VNA**
+
+ Say: "Calibrate device 0009876543 for 144 to 148 MHz"
+
+ Repeat the same procedure with the second VNA's calibration standards.
+
+ Say: "Save calibration to slot 1"
+
+
+
+
+
+## Run a Synchronized Sweep
+
+Now connect your antennas—one to each VNA's Port 1.
+
+
+1. **Run sync_sweep**
+
+ Say: "Run a synchronized sweep on both VNAs from 144 to 148 MHz"
+
+ The assistant calls:
+
+ ```
+ sync_sweep(
+ device_ids=["0001234567", "0009876543"],
+ start_hz=144000000,
+ stop_hz=148000000,
+ points=101
+ )
+ ```
+
+2. **Review the results**
+
+ You'll get S11 data from both devices, swept at the same time (within ±2-5ms).
+
+
+
+## Compare Antenna Performance
+
+
+1. **Run multi_antenna_compare**
+
+ Say: "Compare my two antennas on the 2m band"
+
+ The assistant calls `multi_antenna_compare()` and returns a comparison table:
+
+ | Metric | Antenna A (0001234567) | Antenna B (0009876543) |
+ |--------|------------------------|------------------------|
+ | Min SWR | 1.15 | 1.32 |
+ | Resonance | 145.2 MHz | 144.8 MHz |
+ | Bandwidth (< 2:1) | 4.1 MHz | 3.2 MHz |
+ | Z at resonance | 48 + j2 Ω | 42 - j8 Ω |
+
+2. **Interpret the results**
+
+ - **Min SWR**: Lower is better. Antenna A has better match.
+ - **Resonance**: Where SWR is lowest. Neither is at band center.
+ - **Bandwidth**: Wider is more versatile. Antenna A has broader coverage.
+ - **Z at resonance**: Closer to 50 Ω is better. Both are reasonable.
+
+
+
+## Understanding the Results
+
+### What Sync Sweep Gives You
+
+Software synchronization (Tier 1) starts both sweeps within 2-5ms of each other. This is adequate for:
+
+- Antenna comparison
+- Signal level measurements
+- SWR/impedance analysis
+
+It's **not** precise enough for:
+
+- Phase measurements between devices
+- Antenna array characterization
+- MIMO testing
+
+For those, you'll need [hardware trigger (Tier 2)](/hardware/trigger-wiring/) or [phase coherent (Tier 3)](/hardware/external-clock/).
+
+### Device Capabilities
+
+Check what sync methods each device supports:
+
+Say: "Check capabilities of device 0001234567"
+
+```json
+{
+ "device_id": "0001234567",
+ "capabilities": {
+ "hardware_trigger": false,
+ "external_clock": false
+ },
+ "tier": 1
+}
+```
+
+Stock firmware shows Tier 1 only. Custom firmware enables Tier 2/3.
+
+## Troubleshooting
+
+### Only one device shows up
+
+1. Check USB connections
+2. Try different USB ports (avoid hubs)
+3. Run `refresh_devices()` to re-scan
+4. Check permissions: `sudo usermod -aG dialout $USER` (Linux)
+
+### Device IDs keep changing
+
+Port paths like `/dev/ttyACM0` can change on reconnect. If available, use the serial number (e.g., `0001234567`) instead—it's stable across reconnects.
+
+### Timing concerns
+
+Tier 1's ±2-5ms is sufficient for most comparisons. If you see inconsistent results, ensure:
+
+- Both VNAs have stable connections
+- Neither is being accessed by another program
+- USB host isn't under heavy load
+
+## Next Steps
+
+- [Multi-VNA Coordination](/mcnanovna/multi-vna/) — Understand all three synchronization tiers
+- [Hardware Trigger Wiring](/hardware/trigger-wiring/) — Achieve ±10-50µs precision
+- [Tool Reference](/mcnanovna/tools/) — All coordination tools