Compare commits
3 Commits
62af53c9d1
...
6314313e1f
| Author | SHA1 | Date | |
|---|---|---|---|
| 6314313e1f | |||
| 5edac3007c | |||
| 0e5553c661 |
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.env
|
||||
*.md
|
||||
@ -1,8 +1,3 @@
|
||||
# Project identifier (prevents container name collisions)
|
||||
COMPOSE_PROJECT=mcnanovna-docs
|
||||
|
||||
# Domain for caddy-docker-proxy
|
||||
DOMAIN=mcnanovna.l.zmesh.systems
|
||||
|
||||
# Mode: prod or dev (used by Makefile to select compose files)
|
||||
DOMAIN=mcnanovna.warehack.ing
|
||||
MODE=prod
|
||||
|
||||
68
Makefile
68
Makefile
@ -1,77 +1,45 @@
|
||||
# mcnanovna docs - Makefile for docker compose management
|
||||
# Usage:
|
||||
# make up - Start production (static site)
|
||||
# make dev - Start development (hot-reload)
|
||||
# make down - Stop containers
|
||||
# make logs - Follow container logs
|
||||
# make build - Rebuild container images
|
||||
# make shell - Open shell in running container
|
||||
.PHONY: prod dev down logs build rebuild shell clean help
|
||||
|
||||
.PHONY: up down logs build rebuild shell dev clean help
|
||||
|
||||
# Load environment variables
|
||||
include .env
|
||||
export
|
||||
|
||||
# Compose command shortcuts
|
||||
COMPOSE := docker compose
|
||||
COMPOSE_DEV := docker compose -f docker-compose.yml -f docker-compose.dev.yml
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@echo "mcnanovna docs - Astro/Starlight documentation site"
|
||||
@echo "mcnanovna docs"
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make up Start production (static Caddy server)"
|
||||
@echo " make dev Start development (Vite hot-reload)"
|
||||
@echo " make down Stop all containers"
|
||||
@echo " make logs Follow container logs"
|
||||
@echo " make build Build production image"
|
||||
@echo " make prod Production (static Caddy)"
|
||||
@echo " make dev Development (Vite hot-reload)"
|
||||
@echo " make down Stop containers"
|
||||
@echo " make logs Follow logs"
|
||||
@echo " make build Build image"
|
||||
@echo " make rebuild Force rebuild (no cache)"
|
||||
@echo " make shell Open shell in running container"
|
||||
@echo " make shell Shell into running container"
|
||||
@echo " make clean Remove containers, images, volumes"
|
||||
@echo ""
|
||||
@echo "Environment:"
|
||||
@echo " DOMAIN = $(DOMAIN)"
|
||||
@echo " MODE = $(MODE)"
|
||||
|
||||
# Production mode
|
||||
up: .env
|
||||
$(COMPOSE) up -d
|
||||
$(COMPOSE) logs -f
|
||||
prod:
|
||||
docker compose up -d --build
|
||||
|
||||
# Development mode with hot-reload
|
||||
dev: .env
|
||||
$(COMPOSE_DEV) up -d --build
|
||||
$(COMPOSE_DEV) logs -f
|
||||
dev:
|
||||
docker compose --profile dev up --build
|
||||
|
||||
# Stop containers
|
||||
down:
|
||||
$(COMPOSE) down
|
||||
$(COMPOSE_DEV) down 2>/dev/null || true
|
||||
docker compose --profile dev down
|
||||
|
||||
# View logs
|
||||
logs:
|
||||
$(COMPOSE) logs -f
|
||||
docker compose logs -f
|
||||
|
||||
# Build image
|
||||
build:
|
||||
$(COMPOSE) build
|
||||
docker compose build
|
||||
|
||||
# Rebuild without cache
|
||||
rebuild:
|
||||
$(COMPOSE) build --no-cache
|
||||
docker compose build --no-cache
|
||||
|
||||
# Shell into running container
|
||||
shell:
|
||||
$(COMPOSE) exec docs sh
|
||||
docker compose exec docs sh
|
||||
|
||||
# Clean everything
|
||||
clean:
|
||||
$(COMPOSE) down -v --rmi local
|
||||
$(COMPOSE_DEV) down -v --rmi local 2>/dev/null || true
|
||||
docker compose --profile dev down -v --rmi local
|
||||
|
||||
# Create .env from example if missing
|
||||
.env:
|
||||
@echo "Creating .env from .env.example..."
|
||||
@cp .env.example .env
|
||||
|
||||
@ -2,7 +2,7 @@ import { defineConfig } from 'astro/config';
|
||||
import starlight from '@astrojs/starlight';
|
||||
|
||||
export default defineConfig({
|
||||
site: 'https://mcnanovna.l.zmesh.systems',
|
||||
site: 'https://mcnanovna.warehack.ing',
|
||||
telemetry: false,
|
||||
devToolbar: { enabled: false },
|
||||
integrations: [
|
||||
@ -15,7 +15,7 @@ export default defineConfig({
|
||||
replacesTitle: false,
|
||||
},
|
||||
social: {
|
||||
github: 'https://git.supported.systems/rf/mcnanovna',
|
||||
github: 'https://git.supported.systems/warehack.ing/mcnanovna',
|
||||
},
|
||||
sidebar: [
|
||||
{
|
||||
@ -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' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
# Development overrides - hot-reload with volume mounts
|
||||
# Usage: docker compose -f docker-compose.yml -f docker-compose.dev.yml up
|
||||
|
||||
services:
|
||||
docs:
|
||||
build:
|
||||
target: dev
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules # Anonymous volume to preserve node_modules
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- ASTRO_TELEMETRY_DISABLED=1
|
||||
- VITE_HMR_HOST=${DOMAIN:-mcnanovna.l.zmesh.systems}
|
||||
labels:
|
||||
# Override reverse proxy to Vite dev server port
|
||||
caddy.reverse_proxy: "{{upstreams 4321}}"
|
||||
|
||||
# WebSocket support for Vite HMR
|
||||
caddy.reverse_proxy.flush_interval: "-1"
|
||||
caddy.reverse_proxy.transport: "http"
|
||||
caddy.reverse_proxy.transport.read_timeout: "0"
|
||||
caddy.reverse_proxy.transport.write_timeout: "0"
|
||||
caddy.reverse_proxy.transport.keepalive: "5m"
|
||||
caddy.reverse_proxy.transport.keepalive_idle_conns: "10"
|
||||
caddy.reverse_proxy.stream_timeout: "24h"
|
||||
caddy.reverse_proxy.stream_close_delay: "5s"
|
||||
@ -10,10 +10,38 @@ services:
|
||||
environment:
|
||||
- ASTRO_TELEMETRY_DISABLED=1
|
||||
labels:
|
||||
# caddy-docker-proxy configuration
|
||||
caddy: ${DOMAIN:-mcnanovna.l.zmesh.systems}
|
||||
caddy: ${DOMAIN:-mcnanovna.warehack.ing}
|
||||
caddy.reverse_proxy: "{{upstreams 80}}"
|
||||
|
||||
docs-dev:
|
||||
build:
|
||||
context: .
|
||||
target: dev
|
||||
container_name: ${COMPOSE_PROJECT:-mcnanovna-docs}-dev
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- dev
|
||||
networks:
|
||||
- caddy
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- ASTRO_TELEMETRY_DISABLED=1
|
||||
- VITE_HMR_HOST=${DOMAIN:-mcnanovna.l.warehack.ing}
|
||||
labels:
|
||||
caddy: ${DOMAIN:-mcnanovna.l.warehack.ing}
|
||||
caddy.reverse_proxy: "{{upstreams 4321}}"
|
||||
caddy.reverse_proxy.flush_interval: "-1"
|
||||
caddy.reverse_proxy.transport: "http"
|
||||
caddy.reverse_proxy.transport.read_timeout: "0"
|
||||
caddy.reverse_proxy.transport.write_timeout: "0"
|
||||
caddy.reverse_proxy.transport.keepalive: "5m"
|
||||
caddy.reverse_proxy.transport.keepalive_idle_conns: "10"
|
||||
caddy.reverse_proxy.stream_timeout: "24h"
|
||||
caddy.reverse_proxy.stream_close_delay: "5s"
|
||||
|
||||
networks:
|
||||
caddy:
|
||||
external: true
|
||||
|
||||
@ -10,10 +10,12 @@ import { Tabs, TabItem, Aside } from '@astrojs/starlight/components';
|
||||
### From PyPI (Recommended)
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Claude Code">
|
||||
<TabItem label="MCP Client">
|
||||
For Claude Code:
|
||||
```bash
|
||||
claude mcp add mcnanovna -- uvx mcnanovna
|
||||
```
|
||||
For other MCP clients, configure `uvx mcnanovna` as a server.
|
||||
</TabItem>
|
||||
<TabItem label="Standalone">
|
||||
```bash
|
||||
@ -53,10 +55,12 @@ MCNANOVNA_WEB_PORT=8080 uv run mcnanovna
|
||||
### From PyPI
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Claude Code">
|
||||
<TabItem label="MCP Client">
|
||||
For Claude Code:
|
||||
```bash
|
||||
claude mcp add mcpositioner -- uvx mcpositioner
|
||||
```
|
||||
For other MCP clients, configure `uvx mcpositioner` as a server.
|
||||
</TabItem>
|
||||
<TabItem label="Standalone">
|
||||
```bash
|
||||
@ -94,15 +98,12 @@ mcpositioner requires the ESP32 positioner hardware. See [Hardware Build](/hardw
|
||||
|
||||
## Both Servers Together
|
||||
|
||||
For automated 3D antenna pattern measurement, run both servers:
|
||||
For automated 3D antenna pattern measurement, add both servers to your MCP client:
|
||||
|
||||
```bash
|
||||
# Add both to Claude Code
|
||||
# Claude Code example
|
||||
claude mcp add mcnanovna -- uvx mcnanovna
|
||||
claude mcp add mcpositioner -- uvx mcpositioner
|
||||
|
||||
# Restart Claude Code to load both
|
||||
claude
|
||||
```
|
||||
|
||||
Then use the `measure_antenna_range` prompt to run automated pattern sweeps.
|
||||
|
||||
@ -7,26 +7,25 @@ import { Steps, Tabs, TabItem, Aside } from '@astrojs/starlight/components';
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Claude Code CLI installed
|
||||
- An MCP client (Claude Code, Cursor, Zed, or any MCP-compatible app)
|
||||
- NanoVNA-H connected via USB
|
||||
- Python 3.11+ (handled automatically by uvx)
|
||||
|
||||
## Installation
|
||||
|
||||
<Steps>
|
||||
1. **Add the MCP server to Claude Code**
|
||||
1. **Add the MCP server to your client**
|
||||
|
||||
For Claude Code:
|
||||
```bash
|
||||
claude mcp add mcnanovna -- uvx mcnanovna
|
||||
```
|
||||
|
||||
2. **Start a new Claude Code session**
|
||||
For other clients, configure `uvx mcnanovna` as an MCP server per your client's documentation.
|
||||
|
||||
```bash
|
||||
claude
|
||||
```
|
||||
2. **Start a new session**
|
||||
|
||||
3. **Ask Claude to use your VNA**
|
||||
3. **Ask your assistant to use your VNA**
|
||||
|
||||
Try these prompts:
|
||||
- "Scan my antenna from 144 to 148 MHz"
|
||||
@ -42,7 +41,7 @@ The VNA auto-connects on first tool call. No configuration needed if using defau
|
||||
|
||||
## Verify Connection
|
||||
|
||||
Ask Claude: "Get VNA info"
|
||||
Try: *"Get VNA info"*
|
||||
|
||||
You should see device details like firmware version, serial number, and frequency range.
|
||||
|
||||
@ -50,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
|
||||
|
||||
|
||||
264
src/content/docs/hardware/external-clock.mdx
Normal file
264
src/content/docs/hardware/external-clock.mdx
Normal file
@ -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.
|
||||
|
||||
<Aside type="caution">
|
||||
This modification requires PCB surgery—cutting traces and soldering to IC pins. It voids your warranty and risks damaging the VNA if done incorrectly. Only proceed if you're comfortable with fine-pitch SMD work.
|
||||
</Aside>
|
||||
|
||||
## 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
|
||||
|
||||
<CardGrid stagger>
|
||||
<Card title="Antenna Arrays" icon="rocket">
|
||||
Phased arrays require known phase relationships between elements. Software or trigger sync alone can't provide phase information.
|
||||
</Card>
|
||||
<Card title="MIMO Systems" icon="laptop">
|
||||
Multiple-input-multiple-output antenna characterization needs coherent phase measurement across all paths.
|
||||
</Card>
|
||||
<Card title="Phase Noise Measurement" icon="star">
|
||||
Comparing oscillator phase noise requires a more stable reference than the internal crystal.
|
||||
</Card>
|
||||
<Card title="Beamforming Verification" icon="seti:satellite">
|
||||
Verify beam patterns and null depths on multi-element antennas.
|
||||
</Card>
|
||||
</CardGrid>
|
||||
|
||||
## 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 |
|
||||
|
||||
<Aside type="tip">
|
||||
For most amateur work, a TCXO is sufficient and much cheaper than an OCXO. The key is that all VNAs share the *same* reference—absolute stability matters less than matching.
|
||||
</Aside>
|
||||
|
||||
## 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
|
||||
|
||||
<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)
|
||||
|
||||
<Aside type="caution">
|
||||
This is the point of no return. Once cut, the VNA won't work without an external clock.
|
||||
</Aside>
|
||||
|
||||
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
|
||||
|
||||
</Steps>
|
||||
|
||||
## 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:
|
||||
|
||||
<Steps>
|
||||
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.
|
||||
|
||||
</Steps>
|
||||
|
||||
## 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
|
||||
232
src/content/docs/hardware/trigger-wiring.mdx
Normal file
232
src/content/docs/hardware/trigger-wiring.mdx
Normal file
@ -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
|
||||
|
||||
<Aside type="caution">
|
||||
This modification requires soldering to small test points. If you're not comfortable with fine soldering, consider having an experienced friend help.
|
||||
</Aside>
|
||||
|
||||
## 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 │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
<Aside type="note">
|
||||
Pin locations vary by board revision. On some boards, these pins are on test points. On others, you may need to solder directly to the MCU. Consult your board's schematic.
|
||||
</Aside>
|
||||
|
||||
## Wiring Steps
|
||||
|
||||
<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
|
||||
|
||||
</Steps>
|
||||
|
||||
## 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
|
||||
}
|
||||
```
|
||||
|
||||
<Aside type="tip">
|
||||
See the NanoVNA-H community firmware for trigger-enabled builds, or build your own from the ChibiOS-based source.
|
||||
</Aside>
|
||||
|
||||
## 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
|
||||
@ -26,7 +26,7 @@ import nanoVNA from '../../assets/hardware/NanoVNA-H-2.jpg';
|
||||
|
||||
## What is this?
|
||||
|
||||
Two MCP servers that let Claude control RF test equipment:
|
||||
Two MCP servers that let LLMs control RF test equipment:
|
||||
|
||||
<CardGrid stagger>
|
||||
<Card title="mcnanovna" icon="document">
|
||||
@ -39,7 +39,7 @@ Two MCP servers that let Claude control RF test equipment:
|
||||
</Card>
|
||||
<Card title="Cross-Server Workflows" icon="rocket">
|
||||
Both servers work together for automated 3D antenna pattern measurement.
|
||||
Claude orchestrates positioning and VNA measurements across the grid.
|
||||
Your assistant orchestrates positioning and VNA measurements across the grid.
|
||||
</Card>
|
||||
<Card title="Web UI" icon="laptop">
|
||||
Optional Three.js 3D viewer for radiation patterns.
|
||||
@ -73,12 +73,12 @@ Direct access to professional RF measurement capabilities:
|
||||
## Quick Install
|
||||
|
||||
```bash
|
||||
# Add both servers to Claude Code
|
||||
# Add both servers (Claude Code example)
|
||||
claude mcp add mcnanovna -- uvx mcnanovna
|
||||
claude mcp add mcpositioner -- uvx mcpositioner
|
||||
```
|
||||
|
||||
Then ask Claude to analyze your antenna, measure a filter, or run a 3D pattern sweep.
|
||||
Then ask your assistant to analyze your antenna, measure a filter, or run a 3D pattern sweep.
|
||||
|
||||
## Hardware
|
||||
|
||||
@ -104,7 +104,7 @@ Then ask Claude to analyze your antenna, measure a filter, or run a 3D pattern s
|
||||
|
||||
## Example Prompts
|
||||
|
||||
Once installed, try asking Claude:
|
||||
Once installed, try prompts like:
|
||||
|
||||
- *"Connect to my NanoVNA and sweep 7.0-7.3 MHz to check my 40m dipole"*
|
||||
- *"Measure the insertion loss of this BPF from 144-148 MHz"*
|
||||
|
||||
321
src/content/docs/mcnanovna/multi-vna.mdx
Normal file
321
src/content/docs/mcnanovna/multi-vna.mdx
Normal file
@ -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
|
||||
|
||||
<CardGrid stagger>
|
||||
<Card title="Tier 1: Software" icon="laptop">
|
||||
**±2-5ms timing**
|
||||
|
||||
Parallel async execution via software. Works with any firmware, no modifications needed.
|
||||
|
||||
Best for: Antenna comparison, SWR checks, signal level surveys
|
||||
</Card>
|
||||
<Card title="Tier 2: Hardware Trigger" icon="seti:pipeline">
|
||||
**±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
|
||||
</Card>
|
||||
<Card title="Tier 3: Phase Coherent" icon="rocket">
|
||||
**±1° phase alignment**
|
||||
|
||||
All VNAs share a 26 MHz clock reference plus hardware trigger.
|
||||
|
||||
Best for: Antenna arrays, MIMO, beamforming, phase noise comparison
|
||||
</Card>
|
||||
</CardGrid>
|
||||
|
||||
## Tier Details
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Tier 1: Software">
|
||||
### 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
|
||||
)
|
||||
```
|
||||
</TabItem>
|
||||
|
||||
<TabItem label="Tier 2: Hardware Trigger">
|
||||
### 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
|
||||
)
|
||||
```
|
||||
</TabItem>
|
||||
|
||||
<TabItem label="Tier 3: Phase Coherent">
|
||||
### 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
|
||||
)
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## 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
|
||||
@ -5,7 +5,7 @@ description: MCP server for NanoVNA-H vector network analyzers
|
||||
|
||||
import { Aside } from '@astrojs/starlight/components';
|
||||
|
||||
mcnanovna gives Claude 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 Claude direct control of NanoVNA-H vector network analyzers over
|
||||
- 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 |
|
||||
@ -49,7 +63,7 @@ Other NanoVNA variants using the same USB serial protocol (VID 0x0483, PID 0x574
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Claude Code │
|
||||
│ MCP Client │
|
||||
│ │ │
|
||||
│ MCP Protocol │
|
||||
│ ▼ │
|
||||
@ -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 │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ description: Guided workflow prompts for mcnanovna
|
||||
|
||||
import { Aside } from '@astrojs/starlight/components';
|
||||
|
||||
Prompts are pre-built conversation templates that guide Claude through multi-step procedures. They set up context and provide step-by-step instructions for common workflows.
|
||||
Prompts are pre-built conversation templates that guide your assistant through multi-step procedures. They set up context and provide step-by-step instructions for common workflows.
|
||||
|
||||
## Available Prompts
|
||||
|
||||
|
||||
@ -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 |
|
||||
|
||||
<Aside type="tip">
|
||||
All 78 original tools accept an optional `device_id` parameter to target a specific VNA. Without it, commands go to the default device (or the only connected device).
|
||||
</Aside>
|
||||
|
||||
## Example Usage
|
||||
|
||||
<Tabs>
|
||||
@ -130,30 +180,46 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||
```
|
||||
User: Scan my antenna from 144 to 148 MHz with 201 points
|
||||
|
||||
Claude uses: sweep(144000000, 148000000, 201)
|
||||
Claude uses: scan(s11=true)
|
||||
Claude uses: analyze()
|
||||
Calls: sweep(144000000, 148000000, 201)
|
||||
Calls: scan(s11=true)
|
||||
Calls: analyze()
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="Filter Analysis">
|
||||
```
|
||||
User: Analyze this bandpass filter from 1 to 500 MHz
|
||||
|
||||
Claude uses: sweep(1000000, 500000000, 201)
|
||||
Claude uses: analyze_filter()
|
||||
Calls: sweep(1000000, 500000000, 201)
|
||||
Calls: analyze_filter()
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="Calibration">
|
||||
```
|
||||
User: Calibrate for the 2m band
|
||||
|
||||
Claude uses: sweep(144000000, 148000000, 101)
|
||||
Claude uses: cal("load") # user connects load
|
||||
Claude uses: cal("open") # user connects open
|
||||
Claude uses: cal("short") # user connects short
|
||||
Claude uses: cal("thru") # user connects through
|
||||
Claude uses: cal("done")
|
||||
Claude uses: save(0)
|
||||
Calls: sweep(144000000, 148000000, 101)
|
||||
Calls: cal("load") # user connects load
|
||||
Calls: cal("open") # user connects open
|
||||
Calls: cal("short") # user connects short
|
||||
Calls: cal("thru") # user connects through
|
||||
Calls: cal("done")
|
||||
Calls: save(0)
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="Multi-VNA">
|
||||
```
|
||||
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()
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -5,7 +5,7 @@ description: MCP server for ESP32 dual-axis antenna positioner
|
||||
|
||||
import { Aside } from '@astrojs/starlight/components';
|
||||
|
||||
mcpositioner gives Claude control of an ESP32-based dual-axis antenna positioner over WiFi. It drives two NEMA 17 stepper motors via TMC2209 drivers for theta (polar, 0-180°) and phi (azimuth, 0-360°) rotation.
|
||||
mcpositioner gives LLMs control of an ESP32-based dual-axis antenna positioner over WiFi. It drives two NEMA 17 stepper motors via TMC2209 drivers for theta (polar, 0-180°) and phi (azimuth, 0-360°) rotation.
|
||||
|
||||
## Purpose
|
||||
|
||||
@ -36,7 +36,7 @@ Full build instructions and KiCad schematics are in the [Hardware section](/hard
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Claude Code │
|
||||
│ MCP Client │
|
||||
│ │ │
|
||||
│ MCP Protocol │
|
||||
│ ▼ │
|
||||
|
||||
@ -86,12 +86,12 @@ This prompt requires both mcpositioner AND mcnanovna MCP servers to be running.
|
||||
|
||||
## Using Prompts
|
||||
|
||||
In Claude Code, invoke prompts by name:
|
||||
Invoke prompts by name:
|
||||
|
||||
```
|
||||
User: Run the measure_pattern_grid prompt for my Yagi on 70cm
|
||||
|
||||
Claude: [Uses measure_pattern_grid prompt with antenna_type="yagi", band="70cm"]
|
||||
[Uses measure_pattern_grid prompt with antenna_type="yagi", band="70cm"]
|
||||
```
|
||||
|
||||
The prompt provides step-by-step guidance, and Claude executes the tools from both mcpositioner and mcnanovna as needed.
|
||||
The prompt provides step-by-step guidance, and your assistant executes the tools from both mcpositioner and mcnanovna as needed.
|
||||
|
||||
@ -11,9 +11,9 @@ This tutorial covers common antenna analysis tasks using mcnanovna.
|
||||
|
||||
The most common antenna measurement is SWR (Standing Wave Ratio) and impedance at the feedpoint.
|
||||
|
||||
Ask Claude: "Analyze my antenna from 144 to 148 MHz"
|
||||
Say: "Analyze my antenna from 144 to 148 MHz"
|
||||
|
||||
Claude will:
|
||||
Your assistant will:
|
||||
1. Run a sweep across the band
|
||||
2. Find the resonant frequency (minimum SWR)
|
||||
3. Calculate impedance at resonance
|
||||
@ -32,17 +32,17 @@ Return loss at resonance: -23.4 dB
|
||||
|
||||
For antennas with multiple resonances (like a multi-band antenna):
|
||||
|
||||
Ask Claude: "Find all resonances from 1 to 30 MHz"
|
||||
Say: "Find all resonances from 1 to 30 MHz"
|
||||
|
||||
Claude uses `analyze_s11_resonance` to find all points where the antenna is resonant.
|
||||
This uses `analyze_s11_resonance` to find all points where the antenna is resonant.
|
||||
|
||||
## Impedance Matching
|
||||
|
||||
If your antenna doesn't match 50Ω, design a matching network:
|
||||
|
||||
Ask Claude: "Design a matching network for 35+j25 ohms at 145 MHz"
|
||||
Say: "Design a matching network for 35+j25 ohms at 145 MHz"
|
||||
|
||||
Claude uses `analyze_lc_match` to compute L-network solutions:
|
||||
This uses `analyze_lc_match` to compute L-network solutions:
|
||||
```
|
||||
Solution 1: Series L (27 nH) + Shunt C (18 pF)
|
||||
Solution 2: Shunt C (12 pF) + Series L (42 nH)
|
||||
@ -57,7 +57,7 @@ Solution 2: Shunt C (12 pF) + Series L (42 nH)
|
||||
- Narrow bandwidth
|
||||
- Figure-8 radiation pattern
|
||||
|
||||
Ask Claude: "Analyze my dipole on 20m"
|
||||
Say: "Analyze my dipole on 20m"
|
||||
</TabItem>
|
||||
<TabItem label="Vertical">
|
||||
**Expected characteristics:**
|
||||
@ -65,7 +65,7 @@ Solution 2: Shunt C (12 pF) + Series L (42 nH)
|
||||
- Needs matching network or radials
|
||||
- Omnidirectional pattern
|
||||
|
||||
Ask Claude: "Analyze my vertical on 40m"
|
||||
Say: "Analyze my vertical on 40m"
|
||||
</TabItem>
|
||||
<TabItem label="Yagi">
|
||||
**Expected characteristics:**
|
||||
@ -73,7 +73,7 @@ Solution 2: Shunt C (12 pF) + Series L (42 nH)
|
||||
- Narrow bandwidth
|
||||
- Directional pattern
|
||||
|
||||
Ask Claude: "Analyze my Yagi from 144 to 148 MHz"
|
||||
Say: "Analyze my Yagi from 144 to 148 MHz"
|
||||
</TabItem>
|
||||
<TabItem label="Loop">
|
||||
**Expected characteristics:**
|
||||
@ -81,7 +81,7 @@ Solution 2: Shunt C (12 pF) + Series L (42 nH)
|
||||
- High Q (narrow bandwidth)
|
||||
- Figure-8 pattern (small loop)
|
||||
|
||||
Ask Claude: "Analyze my magnetic loop on 40m"
|
||||
Say: "Analyze my magnetic loop on 40m"
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -114,7 +114,7 @@ For a dipole, each side is approximately λ/4 in length. At 145 MHz, that's abou
|
||||
|
||||
The antenna is resonant but not at 50Ω.
|
||||
|
||||
Ask Claude: "Design a matching network for my measured impedance"
|
||||
Say: "Design a matching network for my measured impedance"
|
||||
|
||||
### Narrow bandwidth
|
||||
|
||||
@ -127,7 +127,7 @@ High-Q antennas (small loops, loaded verticals) have narrow bandwidth. Options:
|
||||
|
||||
For a quick analytical pattern based on antenna type:
|
||||
|
||||
Ask Claude: "Show the radiation pattern for my dipole"
|
||||
Say: "Show the radiation pattern for my dipole"
|
||||
|
||||
This uses the S11 data to determine resonance and impedance, then generates an idealized 3D pattern.
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ An SMA calibration kit includes precision standards. For casual use, a 50Ω term
|
||||
<Steps>
|
||||
1. **Set the sweep range**
|
||||
|
||||
Ask Claude: "Set sweep from 144 to 148 MHz with 101 points"
|
||||
Say: "Set sweep from 144 to 148 MHz with 101 points"
|
||||
|
||||
Calibration is frequency-specific. Always calibrate at the frequencies you'll measure.
|
||||
|
||||
@ -42,43 +42,43 @@ An SMA calibration kit includes precision standards. For casual use, a 50Ω term
|
||||
|
||||
Connect the 50Ω load termination to Port 1.
|
||||
|
||||
Ask Claude: "Run cal load"
|
||||
Say: "Run cal load"
|
||||
|
||||
3. **Connect the OPEN**
|
||||
|
||||
Remove the load, leave Port 1 open (or use an open standard).
|
||||
|
||||
Ask Claude: "Run cal open"
|
||||
Say: "Run cal open"
|
||||
|
||||
4. **Connect the SHORT**
|
||||
|
||||
Connect the short standard to Port 1.
|
||||
|
||||
Ask Claude: "Run cal short"
|
||||
Say: "Run cal short"
|
||||
|
||||
5. **Connect the THROUGH**
|
||||
|
||||
Connect Port 1 to Port 2 with a short cable or barrel adapter.
|
||||
|
||||
Ask Claude: "Run cal thru"
|
||||
Say: "Run cal thru"
|
||||
|
||||
6. **Optional: Isolation**
|
||||
|
||||
Connect 50Ω loads to both ports.
|
||||
|
||||
Ask Claude: "Run cal isoln"
|
||||
Say: "Run cal isoln"
|
||||
|
||||
This corrects for crosstalk between ports.
|
||||
|
||||
7. **Apply calibration**
|
||||
|
||||
Ask Claude: "Run cal done"
|
||||
Say: "Run cal done"
|
||||
|
||||
This computes and applies the error correction coefficients.
|
||||
|
||||
8. **Save calibration**
|
||||
|
||||
Ask Claude: "Save calibration to slot 0"
|
||||
Say: "Save calibration to slot 0"
|
||||
|
||||
Saves to NanoVNA flash for later recall.
|
||||
</Steps>
|
||||
@ -109,7 +109,7 @@ Each slot holds one calibration. Common approach:
|
||||
|
||||
## Recalling Calibration
|
||||
|
||||
Ask Claude: "Recall calibration from slot 0"
|
||||
Say: "Recall calibration from slot 0"
|
||||
|
||||
The NanoVNA will use the stored calibration. Note that calibration must match the current sweep settings.
|
||||
|
||||
|
||||
222
src/content/docs/tutorials/multi-vna-basics.mdx
Normal file
222
src/content/docs/tutorials/multi-vna-basics.mdx
Normal file
@ -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
|
||||
|
||||
<Aside type="note">
|
||||
This tutorial uses Tier 1 (software) synchronization, which works with any NanoVNA firmware. No modifications needed.
|
||||
</Aside>
|
||||
|
||||
## Discover Your Devices
|
||||
|
||||
<Steps>
|
||||
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 |
|
||||
|
||||
</Steps>
|
||||
|
||||
## 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"
|
||||
|
||||
<Aside type="tip">
|
||||
When only one VNA is connected, it becomes the default automatically. Multi-VNA targeting only matters when you have multiple devices.
|
||||
</Aside>
|
||||
|
||||
## Calibrate Each VNA
|
||||
|
||||
<Steps>
|
||||
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"
|
||||
|
||||
</Steps>
|
||||
|
||||
<Aside type="caution">
|
||||
Use the same frequency range for both VNAs. Calibrate each with its own cables and adapters—the ones you'll use for measurement.
|
||||
</Aside>
|
||||
|
||||
## Run a Synchronized Sweep
|
||||
|
||||
Now connect your antennas—one to each VNA's Port 1.
|
||||
|
||||
<Steps>
|
||||
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).
|
||||
|
||||
</Steps>
|
||||
|
||||
## Compare Antenna Performance
|
||||
|
||||
<Steps>
|
||||
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.
|
||||
|
||||
</Steps>
|
||||
|
||||
## 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
|
||||
@ -11,7 +11,7 @@ This tutorial walks through measuring a complete 3D antenna radiation pattern us
|
||||
|
||||
- NanoVNA-H connected via USB
|
||||
- ESP32 positioner built and on WiFi
|
||||
- Both MCP servers added to Claude Code:
|
||||
- Both MCP servers added to your client (e.g., for Claude Code):
|
||||
```bash
|
||||
claude mcp add mcnanovna -- uvx mcnanovna
|
||||
claude mcp add mcpositioner -- uvx mcpositioner
|
||||
@ -56,27 +56,27 @@ For accurate patterns, the transmit antenna should have a known, broad pattern (
|
||||
<Steps>
|
||||
1. **Verify both servers are connected**
|
||||
|
||||
Ask Claude: "Check positioner status and VNA info"
|
||||
Say: "Check positioner status and VNA info"
|
||||
|
||||
Claude will call `positioner_status` and `info` to verify both devices respond.
|
||||
This will call `positioner_status` and `info` to verify both devices respond.
|
||||
|
||||
2. **Home the positioner**
|
||||
|
||||
Ask Claude: "Home the positioner on both axes"
|
||||
Say: "Home the positioner on both axes"
|
||||
|
||||
This establishes the reference position (theta=0, phi=0).
|
||||
|
||||
3. **Calibrate the VNA**
|
||||
|
||||
Ask Claude: "Calibrate for the 2m band"
|
||||
Say: "Calibrate for the 2m band"
|
||||
|
||||
Follow the SOLT calibration procedure. This is critical for accurate S21 measurements.
|
||||
|
||||
4. **Run the pattern measurement**
|
||||
|
||||
Ask Claude: "Measure a 3D radiation pattern for my dipole antenna on 2m"
|
||||
Say: "Measure a 3D radiation pattern for my dipole antenna on 2m"
|
||||
|
||||
Claude uses the `measure_pattern_grid` prompt to guide the measurement:
|
||||
This uses the `measure_pattern_grid` prompt to guide the measurement:
|
||||
- Confirms grid resolution (default: 5° theta × 10° phi)
|
||||
- Moves through each grid point in serpentine order
|
||||
- Measures S21 at each position
|
||||
@ -86,7 +86,7 @@ For accurate patterns, the transmit antenna should have a known, broad pattern (
|
||||
|
||||
If the mcnanovna web UI is running (`MCNANOVNA_WEB_PORT=8080`), the pattern renders in 3D automatically.
|
||||
|
||||
Or ask Claude: "Show the pattern statistics"
|
||||
Or say: *"Show the pattern statistics"*
|
||||
</Steps>
|
||||
|
||||
## Resolution Tradeoffs
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user