Web workbench
The web workbench is the live, no-install face of antennaknobs: a panel of knobs per design, with the radiation pattern, SWR, and impedance re-solving as you drag.
Run it locally
Section titled “Run it locally”pip install "antennaknobs[web]"uvicorn antennaknobs.web.server:app # http://127.0.0.1:8000The [web] extra pulls in uvicorn[standard], which provides the WebSocket
support the live-solve channel (/ws) needs — plain uvicorn fails that
handshake.
The hosted instance
Section titled “The hosted instance”A hosted simulator is running at
app.antennaknobs.dev (a single
FastAPI process serving the API, the /ws live-solve channel, and the built
React SPA). It’s deployed as a container on Fly.io; the repo’s docs/deploy.md
is the runbook.
Driving a knob
Section titled “Driving a knob”Each parameter in a design is a knob (the big one is the measurement-frequency VFO dial; the rest are smaller). Three ways to change one:
- Drag — press on the knob and move the mouse vertically (up to increase, down to decrease). Horizontal motion is ignored, so a natural hand motion won’t fight you.
- Keyboard / physical dial — click a knob (or tab to it) to select it; it stays highlighted as the armed knob. Then ↑ / → and ↓ / ← step by one increment, Page Up / Down by ten, Home / End jump to the range ends, and Enter opens the value to type a number exactly. The selection is sticky — it survives clicking away (onto the 3D view, say), so a physical USB dial that emits arrow keys keeps driving the armed knob without having to hold keyboard focus on it. Esc disarms.
- Right-click menu — right-click a knob for its settings:
- Turn step — how much one drag-notch / arrow press moves the value.
- Display range — the min/max the knob sweeps between.
- Optimize this knob + Optimize range — mark it as a free variable for the optimizer and bound its search (see Optimizing below).
Every turn re-solves and redraws live (when Live is on — see below).
Live & paused solving
Section titled “Live & paused solving”A Live toggle sits next to the frequency dial. It looks depressed when on and raised when off:
- On — every knob turn triggers a solve; the plots track your hand.
- Paused — knob turns just move the values; nothing solves until you turn Live back on. Useful when you want to set several knobs before paying for a solve, or when a heavy design makes continuous solving sluggish.
Optimizing
Section titled “Optimizing”Next to Live is an Optimize toggle (same depressed-when-on look), with a gear menu beside it for the objective. The optimizer continuously tunes the knobs you’ve marked to hit a target:
- Pick an objective in the gear menu:
- Resonance — drive the feed-point reactance to zero (X → 0).
- SWR — minimize SWR against the design’s reference impedance (Z₀, 50 Ω by default).
- Mark the knobs to vary — right-click each knob you’ll let the optimizer move, check Optimize this knob, and set its Optimize range (the search bounds). A marked knob is visually flagged.
- Turn on Optimize. While Live is also on, the optimizer runs reactively: any time you change a fixed knob, it re-tunes the marked knobs (a short debounce, then a few dozen solves) and writes the best values back, so the antenna stays on target as you explore.
Under the hood it’s a derivative-free Nelder–Mead search (each evaluation is a full MoM solve), bounded by your Optimize ranges, and it always runs on the fast momwire engine — never PyNEC, which is too slow for an interactive loop. It’s a tuning aid, not a global optimizer: give it sensible ranges and a couple of free knobs, not a dozen.
Choosing a solver & segment count
Section titled “Choosing a solver & segment count”A solver selector offers a few preset slots so you can flip between engines without re-entering options — e.g. a fast dense basis, an accelerated array engine, and the PyNEC reference. The available engines are the momwire bases (triangular, sinusoidal, bspline), the accelerators (hmatrix, arrayblock), and the optional PyNEC backend — see The solver & accuracy for what each is good at.
The solver’s gear menu also exposes segments / wire (N) — how finely each wire is discretized. More segments = more accurate (up to convergence) but a larger, slower solve. See Segments & convergence for what N means and how to find “enough.”
Convergence sweep
Section titled “Convergence sweep”To check that your chosen N is converged — i.e. adding more segments no longer moves the impedance — run a convergence sweep. It re-solves the current antenna across a range of N values and plots the resulting feed-point impedance, so you can see where the curve flattens out. Details and how to read it: Segments & convergence.
Design sessions (tabs)
Section titled “Design sessions (tabs)”The sidebar is a notebook: the tabs across its top (D1, D2, …) are independent design sessions, each with its own geometry, knob values, design and measurement frequency, ground setting, solver slot, and results. Click + to open a new session — it starts fresh and solves on its own — switch by clicking a tab, and close one with the ✕ (the last remaining tab can’t be closed).
- Sessions are fully independent: changing a knob, the solver, or the ground model in one leaves every other session exactly as you left it.
- Hover a tab for its summary — design, solver, segment count, and ground
model — e.g.
dipoles.invvee · Triangular N=40 · free space. - Switching to a session re-solves it, which is near-instant because the server caches recent solves (see How a knob turn works).
- The light/dark theme is shared across all sessions; everything else is per-session.
Open the same design in two tabs to compare tunings, or load two different antennas — then pair it with pattern pinning to overlay one session’s radiation pattern on another’s.
Comparing patterns
Section titled “Comparing patterns”On the azimuth and elevation pattern views a 📌 Pin pattern button (top-left of the plot) freezes the current radiation pattern as a dimmed, dashed ghost overlaid on the live one. Pin it, then change knobs — or switch to a completely different design — and the live lobe redraws over the pinned ghost so you can see the effect directly.
- Pins survive a design switch, so you can overlay one antenna’s pattern on another’s — a Yagi’s beam against a dipole’s figure-8, say — not just two tunings of the same design.
- Each pinned trace recomputes for whichever cut (azimuth or elevation) and cut-angle you’re viewing, so it always shares the live plot’s geometry.
- A compare table appears alongside with a row per pattern — peak gain (dBi), takeoff angle, front-to-back, and −3 dB azimuth beamwidth — so the overlaid shapes come with the numbers that matter. clear removes all pins; the ✕ on a row removes one.
Copying params back to code
Section titled “Copying params back to code”The gear menu (⚙, top of the sidebar) has Copy params (Python), which
copies the current knob values to the clipboard as a paste-ready
default_params = {...} block (a <variant>_params block when you’re on a
named variant). Drop it straight into a design file to bake in whatever you
dialed in — no more transcribing values off the screen by hand.
The same gear menu also has Download .nec deck, which exports the design as a NEC-2 card deck for xnec2c / 4nec2 / EZNEC.
How a knob turn works
Section titled “How a knob turn works”A knob change sends one message over the /ws WebSocket; the server re-solves in
a worker thread and sends the result back. Perceived latency is dominated by the
solve time (free-space dipole-class solves are tens of milliseconds), not the
network — so a regional server feels responsive for live tuning. Repeated solves
of the same request hit a server-side cache, so flicking a knob back to a prior
value is instant.