How to read this notebook
Logs 1 and 2 set out the problem and give an overview of the toolkit. Logs 3 to 9 each cover one part of it: the need it answers, what the code does function by function, and real output from testing on hardware. Every log carries a tag that says how far along that part is.
- Overview:
- background, not code.
- Tested on hardware:
- run against the real device, with the output checked.
- Partly working:
- runs, but one part isn't confirmed yet.
- Not working yet:
- written and connected, but not producing results yet.
- Planned:
- the next steps, in order.
Box colours
The software was written with help from Claude AI. Each part was tested against the real hardware before we relied on it, and the problems those tests turned up are in the logs. If we get something wrong, we'll correct it here in the open and say what changed.
The need
A vector network analyzer sends a signal into a device and measures what comes back and what gets through, at each frequency. That tells you how well an antenna is matched, how much a cable loses, or what a filter passes. Bench VNAs stay on the bench. The small battery-powered NanoVNA family can be carried, or flown, which opens up a different kind of measurement: how a device's response changes as it moves.
That only works if every sweep comes with the place it was taken. When we tried to do it, the hard part wasn't the radio. It was everything around it.
Need 1.1 (the two numbers a VNA gives you). At each frequency, \(S_{11}\) is the fraction of the signal sent into port 1 that reflects back, and \(S_{21}\) is the fraction that arrives at port 2. Both are complex numbers: a size and a phase shift. In decibels, the return loss is
$$\text{RL} = -20\log_{10}|S_{11}|. \tag{1.1}$$A well-matched antenna reflects little (high return loss). An open or shorted cable reflects everything (\(|S_{11}| = 1\), 0 dB).[1]
Need 1.2 (a position-tagged sweep). What we want from every measurement: the list of frequencies with \(S_{11}\) and \(S_{21}\) at each, saved together with the GPS fix (position, accuracy, time) taken at the same moment, in a format any RF tool can open.
What stands in the way, and what answers it
| The need | Why it's hard today | What answers it |
|---|---|---|
| Run the analyzer from a small Linux computer, without vendor desktop software | The PC program we started with, Solver64, is Windows-only, and a desktop app doesn't suit a Raspberry Pi strapped to something moving. | litevna.py, nanovna_classic.py |
| Work with whichever NanoVNA is plugged in | NanoVNA models speak two unrelated protocols, and detecting the wrong way can upset the analyzer. | nanovna.py |
| Know where each sweep was taken | The GPS logs separately. Matching two files by timestamp afterwards is slow and easy to get wrong. | gps_dr.py, capture_combined.py |
| Never save bad data without saying so | One analyzer we tested returned sweeps that were mostly empty, with no error. | The sweep check in nanovna_classic.py |
| Open the results in any RF tool | Custom formats lock the data into one program. | Standard Touchstone .s2p files (Log 3, Log 7)[2] |
| Start with one button, even on a Pi with no internet | Python setups break easily when copied between machines, and an offline Pi can't download anything. | record.sh, install_launcher.sh, offline_packages/ |
The toolkit at a glance
The toolkit is a folder of plain Python scripts. Its only dependencies are pySerial, numpy, matplotlib and pyubx2.[7][6] Pressing Record runs the chain below.
Every file, and the need it serves
| File | Role | Need it serves |
|---|---|---|
litevna.py | Driver | Run a LiteVNA or NanoVNA-V2 from Python (Log 3) |
nanovna_classic.py | Driver | Run the older text-command NanoVNAs, and catch bad sweeps (Log 4) |
nanovna.py | Driver | Find and connect to any NanoVNA automatically (Log 5) |
gps_dr.py | Driver | Read position and dead-reckoning status from the GPS (Log 6) |
capture_combined.py | Main tool | One file per sweep with its GPS fix (Log 7) |
vna_measure.py, vna_live.py, gps_live.py | Other tools | A quick single sweep, live viewing of several analyzers, and a GPS-only track (Log 8) |
record.sh, run_vna_live.sh, install_launcher.sh, Record.desktop | Launchers | Start everything from one icon (Log 7, Log 9) |
offline_packages/ | Setup | Install on a Pi with no internet (Log 9) |
README.txt | Docs | Copy-and-paste setup for a new machine, and a guide to every file |
Hardware
| Part | Role | Where to buy |
|---|---|---|
| LiteVNA (ZeenKo) | Main analyzer. Swept 1 MHz–3 GHz in our tests. | Search |
| NanoVNA-H | Second analyzer, the older text-command type. | Search |
| NanoVNA-F V2 (SYSJOINT) | Third analyzer. Its firmware returns mostly empty sweeps (Log 4). | Search |
| Raspberry Pi 4 Model B | Field computer that runs the logger. | Search |
| SparkFun GPS-RTK Dead Reckoning pHAT (u-blox ZED-F9R) | GPS with a built-in motion sensor for dead reckoning. Plugs onto the Pi's GPIO header. | SparkFun GPS-16475 |
| GNSS antenna with U.FL connector | The GPS board won't get a fix without one. | Search |
litevna.py: talking to a LiteVNA without vendor software
Need 3.1. Control a LiteVNA or NanoVNA-V2 from plain Python on Linux, with nothing but a USB cable and the pyserial library.
The code 3.2. These analyzers speak a binary register protocol: short commands such as READ (0x10), WRITE (0x20) and READFIFO (0x18), each aimed at a numbered register.[4]
LiteVNA(port)opens the USB serial port in raw mode. Without raw mode, Linux's terminal layer alters some binary bytes. It can also take an already-open connection, so a port is never closed and reopened (Log 5).set_sweep(start, stop, points)writes the start frequency, step and number of points into the analyzer's registers. It only accepts the point counts the hardware supports (51, 101, 201 … 25601), and refuses anything else with a clear error instead of quietly changing your request.sweep()reads the results in chunks of up to 255 points, 32 bytes each: the forward, reflected and through signals plus a frequency index. It computes \(S_{11}\) and \(S_{21}\) from them and retries twice if a read comes back incomplete.firmware_string()andread_vbat()report the firmware version and battery voltage.save_s1p()andsave_s2p()write standard Touchstone files that any RF tool can open.
The analyzer measures a sample of the outgoing signal \(v_f\), the reflected signal \(v_r\) and the through signal \(v_t\). The driver divides:
$$S_{11}=\frac{v_r}{v_f},\qquad S_{21}=\frac{v_t}{v_f}. \tag{3.1}$$Dividing by the outgoing signal cancels any drift in the source's strength from sweep to sweep.
Output 3.3. A one-shot sweep with nothing attached to the port, August 26, 2026:
Connected: /dev/ttyACM0 FW 2.2 HW variant 2 rev 2 Battery: 3.72 V Sweeping 1.000-3000.000 MHz, 51 points... Saved measurement.s2p
The file's first point reads \(S_{11} = 1.000555 - 0.024789i\) at 1 MHz: a magnitude of 1.0009, almost exactly the 1 that an open port should give. A second run minutes later, by a different program, agreed to within \(5.3\times10^{-4}\).
Asking for 21 points, which the hardware can't do, gets a clear refusal:
ValueError: points must be one of (51, 101, 201, 401, 801, 1024, 1601, 3201, 4501, 6401, 12801, 25601)
Note 3.4 (speed). At first the driver entered the analyzer's raw-sample mode for every sweep and left it afterwards. Re-entering that mode is slow because the analyzer re-locks each time. Staying in it between sweeps cut a 51-point sweep from about 300 ms to about 170 ms: 5.86 sweeps per second, the most this analyzer can do.
Note 3.5 (what the numbers are and aren't). The LiteVNA only sends from port 1, so the two other S-parameters (\(S_{12}\), \(S_{22}\)) are never measured. The two-port file format still needs them, so the files set \(S_{12}=S_{21}\) and \(S_{22}=0\) and say so in a comment. The readings are also uncalibrated: raw ratios, before any correction with known reference loads. Adding calibration is in Log 10.
nanovna_classic.py: older NanoVNAs that speak text
Need 4.1. Support the original NanoVNA and the H, H4 and F models, which use a text command line instead of binary registers, behind exactly the same functions as the LiteVNA driver. Never pass on a sweep the analyzer didn't actually measure.
The code 4.2. These analyzers show a ch> prompt and take typed commands.[3]
detect(ser)sends a carriage return and looks for thech>prompt. It only runs after the binary check has failed (Log 5).NanoVNAClassic(port)reads the firmware version and picks the right sweep command for it:scanwith an output mask on firmware 0.7.1 and later, plainscanfrom 0.2.0, andsweepbefore that._exec(command)sends a command and collects the reply lines until the prompt returns. It waits longer for bigger sweeps, so a slow analyzer isn't mistaken for a dead one.set_sweep()andsweep()have the same names and meaning as in the LiteVNA driver.sweep()reads \(S_{11}\) fromdata 0and \(S_{21}\) fromdata 1, one line per frequency._check_sweep_complete()rejects any sweep in which more than 10% of the points read exactly zero for both \(S_{11}\) and \(S_{21}\).
Output 4.3 (the clone that skipped most of each sweep). A NanoVNA-F V2 returned the right number of points, but every point after a cutoff read exactly 0.000000 0.000000, with no error. Before the check existed, those zeros were being saved as if they were measurements. Now the logger reports it and tries again:
[VNA] lost connection (Incomplete sweep: 36/51 points never measured (device returned exact 0+0j for both S11 and S21)); searching again...
| Requested | Measured | Fraction |
|---|---|---|
| 11 | 3 | 27% |
| 21 | 6 | 29% |
| 51 | 15 | 29% |
| 101 | 29 | 29% |
| 201 | 58 | 29% |
The measured points are always the lowest frequencies. The cutoff didn't move with waits of up to 10 s, with re-triggering, or with a different sweep command. The zeros are already in the text the analyzer sends, so this is in its firmware and can't be fixed from the computer.
Note 4.4 (why the check is safe). A real measurement essentially never reads exactly zero for both values at once. Even a good 50 Ω load still reflects about 1%. So the check only looks for a sign that the instrument failed, and never throws out a reading just because it looks unexpected.
Note 4.5. A NanoVNA-H worked correctly through this driver, with complete sweeps at 2.71 per second (Log 8).
nanovna.py: plug in any NanoVNA
Need 5.1. Plug in any NanoVNA, on any USB port, and have it just work, without the user knowing which protocol it speaks or which port it landed on. Also handle several analyzers at once.
The code 5.2.
_candidate_ports()lists every USB serial port:/dev/ttyACM*and/dev/ttyUSB*._looks_like_v2()checks for the binary protocol in a harmless way: a protocol reset (eight zero bytes), then a read of two firmware registers. A text shell that just echoes the bytes back isn't mistaken for a reply._probe_port()tries the binary check first, then the text check only if that fails, and hands the same open connection to the matching driver.find_and_open()returns the first analyzer found.connect(port)does the same for one named port.device_id_for_port()gives each analyzer a stable name from/dev/serial/by-id, such asusb-ZeenKo.tech_LiteVNA6_v1.0-if00, so its files keep the same name when it's unplugged and plugged back in.probe_all()returns every connected analyzer, for running several at once.
Both drivers offer the same functions (set_sweep, sweep, firmware_string, read_vbat, close), so the tools never need to know which kind they got.
Note 5.3 (why the order of the checks matters). Our first version tried the text check first. A carriage return is the byte 0x0D, which in the binary protocol is itself a command. Sending it knocked a real LiteVNA out of binary mode. Trying the harmless binary read first means a binary analyzer never sees that byte.
Note 5.4 (why the connection is reused). Closing the port after the check and opening it again for the driver made the LiteVNA unstable, most likely because closing the port toggles a USB control line that resets it. Handing over the open connection fixed it.
Output 5.5. The same call found each of our three analyzers and picked the right driver. The LiteVNA was found by the binary check:
[VNA] connected on /dev/ttyACM0: FW 2.2 HW variant 2 rev 2
The NanoVNA-F V2 failed the binary check and answered the text check:
Model: NanoVNA-F_V2 Frequency: 50k ~ 3GHz Build time: Jun 18 2025 - 13:48:38 CST
gps_dr.py: reading the GPS
Need 6.1. Get position, its accuracy, and whether the receiver is filling gaps with dead reckoning, from the ZED-F9R on the Pi. Do it without changing any setting the module keeps after a power cycle.
The code 6.2. It uses u-blox's binary UBX messages, read with the pyubx2 library.[5][6]
find_port()picks the first of/dev/serial0,/dev/ttyAMA0and/dev/ttyS0that exists.GPSReceiver(port, baudrate=115200, rate_hz=5)opens the Pi's serial port and a UBX reader on it._configure()sends one configuration message that sets 5 fixes per second and turns on two outputs: NAV-PVT (position, velocity, time) and ESF-STATUS (sensor fusion). It writes to the module's temporary memory only, so a power cycle puts the module back exactly as it was.read_fix()waits up to 2 s for the next NAV-PVT and returns aGNSSFix: latitude and longitude, height, horizontal and vertical accuracy, ground speed, heading, satellite count, fix type, and the latest fusion mode. It converts the module's millimetres to metres.fix_to_csv_row()andCSV_HEADERturn a fix into one line of text for the output files.
Note 6.3 (why UBX and not the usual NMEA text). Most GPS tools read NMEA, the common text output. NMEA doesn't report whether the ZED-F9R is blending satellites with its motion sensor. UBX does, so every saved fix says whether its position came from satellites, from dead reckoning (under trees or a bridge), or both.
Note 6.4 (Pi setup). The GPS board talks over the Pi's GPIO serial port, which has to be switched on in raspi-config, with the login shell over serial turned off. On a Pi 4, Bluetooth uses the better of the Pi's two serial ports by default. Adding dtoverlay=disable-bt to /boot/firmware/config.txt hands that port to the GPIO pins instead. The project README has the exact steps.
Status: the code connects to the module on the Pi and the module responds, but no fix has come through yet. At 115200 baud, the speed the code assumes, the serial port shows garbled characters, which points to a speed mismatch. Finding the module's real speed is the first step in Log 10.
capture_combined.py: one button, one file per sweep
Need 7.1. Every sweep should carry its own position, with nothing to match up afterwards, and the whole thing should start from one icon and keep going if a cable drops.
The code 7.2.
GPSFeederruns in the background. It keeps the GPS open, always holds the newest fix (latest_fix()), and reconnects by itself if the GPS drops, so a GPS problem never stops the VNA logging.main()searches for an analyzer every second, printing "still searching" every 5 s. Once one is found, it sets the sweep (1 MHz–3 GHz, 51 points by default), then loops: sweep, take the newest fix, write a file, print a status line. If the analyzer drops or returns a bad sweep, it goes back to searching.write_combined_file()writes the GPS fix as comment lines at the top, then the normal S-parameter data.timestamped_path()names each file by the time to the millisecond, for examplecapture_20260826_081717_721.s2p, so files sort in order and never overwrite each other.CAPTURE_INTERVAL_SECONDS, a clearly marked number at the top of the file, sets how often a file is written. Setting it to 0 writes one for every sweep.--intervalchanges it for a single run.record.shis what the Record icon runs. It uses the project's own Python environment if there is one, and the system Python if not, and keeps the window open at the end so any message can be read.
The file it writes
The start of a real file from a test with no GPS attached:
! Generated by capture_combined.py ! GPS no fix available at capture time ! S12 assumed = S21 (reciprocity); S22 not measured by this single forward-sweep hardware and set to 0 # Hz S RI R 50 1000000 1.000727e+00 -2.528906e-02 9.154901e-07 5.808659e-06 9.154901e-07 5.808659e-06 0.000000e+00 0.000000e+00 60980000 2.253148e-01 -9.952042e-01 1.315307e-05 -1.283828e-05 1.315307e-05 -1.283828e-05 0.000000e+00 0.000000e+00 …
With a fix, the second line becomes two lines: a list of column names, then the values. They are time, fix type, number of satellites, latitude, longitude, height, horizontal and vertical accuracy, ground speed, heading, and dead-reckoning fusion mode.
In the Touchstone format, lines that start with ! are comments.[2] Every file still opens in standard RF software, and the position travels inside the measurement it belongs to.
Note 7.3 (how closely the fix matches the sweep). At 5 fixes per second, the newest fix is never more than 0.2 s old when a sweep finishes, and a 51-point sweep takes 0.17 s. So a sweep and its fix are at most about 0.2 s apart, plus the short delay for the fix to arrive over the serial port. Moving at speed \(v\), that is a position mismatch of roughly
$$\Delta x \approx v \times 0.2\ \text{s}: \quad 0.3\ \text{m walking},\qquad 2\ \text{m for a drone at 10 m/s}. \tag{7.1}$$Output 7.4. A 30-second run with the LiteVNA and the interval set to 1 s, August 26, 2026, on a computer with no GPS attached:
Searching for NanoVNA... [GPS] searching... (Could not configure port: (5, 'Input/output error')) [VNA] connected on /dev/ttyACM0: FW 2.2 HW variant 2 rev 2 [capture 1] captures/capture_20260826_081717_721.s2p (no GPS fix yet, 2.24/s) [capture 2] captures/capture_20260826_081718_723.s2p (no GPS fix yet, 1.38/s) … [capture 32] captures/capture_20260826_081748_752.s2p (no GPS fix yet, 1.02/s)
It wrote 32 files, every one with all 51 points, settling to 1.02 files per second. It also shows the logger doing what it should with no GPS: it says so plainly in every file and on screen, and keeps recording the VNA.
What the recorded files show
\(|S_{11}|\) with the port open, 142 sweeps: median line, lowest-to-highest band (uncalibrated)
Show the numbers as a table
| MHz | Median (dB) | Lowest (dB) | Highest (dB) |
|---|---|---|---|
| 1.00 | +0.009 | +0.005 | +0.013 |
| 60.98 | +0.173 | +0.165 | +0.180 |
| 120.96 | -0.156 | -0.161 | -0.152 |
| 180.94 | +0.054 | +0.046 | +0.062 |
| 240.92 | -0.023 | -0.028 | -0.000 |
| 300.90 | -0.372 | -0.376 | -0.344 |
| 360.88 | -0.024 | -0.030 | +0.003 |
| 420.86 | +0.415 | +0.407 | +0.502 |
| 480.84 | +0.132 | +0.126 | +0.281 |
| 540.82 | -0.885 | -0.891 | -0.767 |
| 600.80 | -1.099 | -1.104 | -1.022 |
| 660.78 | -0.021 | -0.029 | +0.054 |
| 720.76 | +0.654 | +0.646 | +0.755 |
| 780.74 | -0.478 | -0.484 | -0.324 |
| 840.72 | -2.594 | -2.605 | -2.404 |
| 900.70 | -1.966 | -1.973 | -1.886 |
| 960.68 | -0.027 | -0.036 | +0.000 |
| 1020.66 | +0.341 | +0.327 | +0.398 |
| 1080.64 | -1.981 | -1.989 | -1.877 |
| 1140.62 | -3.860 | -3.868 | -3.782 |
| 1200.60 | -2.214 | -2.220 | -2.196 |
| 1260.58 | -0.651 | -0.656 | -0.581 |
| 1320.56 | -2.127 | -2.136 | -1.817 |
| 1380.54 | -5.773 | -5.786 | -5.264 |
| 1440.52 | -6.032 | -6.041 | -5.695 |
| 1500.50 | -3.073 | -3.080 | -2.861 |
| 1560.48 | -1.882 | -1.886 | -1.685 |
| 1620.46 | -2.880 | -2.890 | -2.670 |
| 1680.44 | -5.765 | -5.774 | -5.449 |
| 1740.42 | -5.373 | -5.393 | -5.097 |
| 1800.40 | -2.430 | -2.447 | -2.262 |
| 1860.38 | -1.476 | -1.486 | -1.357 |
| 1920.36 | -2.740 | -2.755 | -2.597 |
| 1980.34 | -5.011 | -5.037 | -4.840 |
| 2040.32 | -3.064 | -3.075 | -3.001 |
| 2100.30 | -1.162 | -1.171 | -1.077 |
| 2160.28 | -1.382 | -1.386 | -1.249 |
| 2220.26 | -3.433 | -3.449 | -3.164 |
| 2280.24 | -5.155 | -5.166 | -4.898 |
| 2340.22 | -2.508 | -2.522 | -2.396 |
| 2400.20 | -1.180 | -1.193 | -1.052 |
| 2460.18 | -1.680 | -1.689 | -1.469 |
| 2520.16 | -4.428 | -4.452 | -4.034 |
| 2580.14 | -4.699 | -4.714 | -4.541 |
| 2640.12 | -1.795 | -1.996 | -1.667 |
| 2700.10 | -0.841 | -0.859 | -0.665 |
| 2760.08 | -2.067 | -2.083 | -1.693 |
| 2820.06 | -5.510 | -5.543 | -4.997 |
| 2880.04 | -3.236 | -3.254 | -3.161 |
| 2940.02 | -0.734 | -0.748 | -0.624 |
| 3000.00 | -0.642 | -0.682 | -0.244 |
Status: the VNA half is tested on hardware. The GPS half of every file stays empty until the GPS link works (Log 6).
The other tools
Not every job needs a file per sweep. These three tools use the same drivers for other everyday needs.
| Tool | Need it serves | What it does |
|---|---|---|
vna_measure.py | "I just want one sweep, a plot and a file." | Connects, sweeps once, saves a .s1p or .s2p file and shows a plot. Options: --start, --stop, --points, --format, --output, --no-plot, --port. |
vna_live.py | "I want to watch one or more analyzers live." | Runs one worker thread per analyzer, each rewriting its own file, captures/live_<device-id>.s2p, after every sweep. Shows a live plot. Analyzers can be unplugged and plugged back in at any time. --no-plot gives the fastest rate. |
gps_live.py | "I want a GPS track on its own." | Appends every fix as a row of a CSV file, captures/gps_<time>.csv, saving after each row so a crash loses nothing. If no message arrives it says so on screen, so a silent receiver never looks like a hang. |
Output 8.1 (two analyzers at once). With vna_live.py running a LiteVNA and a NanoVNA-H together, the LiteVNA held 5.86 sweeps per second, as fast as on its own, and the NanoVNA-H ran at 2.71. Each wrote its own file, with no interference.
Note 8.2 (a faster live plot). At first the plot only redrew once a second, because redrawing waited on the device check. Now the plot has its own refresh timer (PLOT_REFRESH_INTERVAL, 0.03 s) and only redraws an analyzer's graph when a new sweep has arrived. Matplotlib's faster "blitting" mode left ghost traces on this Linux setup, so the plot redraws in full.
Setting up a Pi with no internet
Need 9.1. The Pi in the field has no internet. Copying the project folder over on a USB stick and running one command should be enough to make the Record icon work.
What broke, and what fixed it
| What broke | Why | Fix |
|---|---|---|
| The Python environment copied from the development PC didn't work on the Pi | It's tied to the PC's processor type (x86-64, while the Pi is ARM), and FAT32/exFAT USB sticks strip the links inside it. | Don't copy it. Install fresh on the Pi. |
pip install failed | pip downloads packages from the internet. | offline_packages/: 15 package files downloaded ahead of time on a machine with internet, for the Pi's exact platform. |
No matching distribution found for numpy | The first set was built for Python 3.10. The Pi runs 3.13, and these files must match the Python version exactly. | Downloaded again for Python 3.13 on ARM64. |
externally-managed-environment | The new environment on the Pi was created without its own pip, so installs fell through to the system Python, which Debian protects.[8] | Install straight into the system Python from the local files. record.sh now uses the system Python when there's no project environment. |
| The Record icon pointed at the wrong computer | Desktop launcher files store full paths, so a copied one still points at the old machine's folder. | install_launcher.sh rewrites Record.desktop for the folder it's in, makes the scripts runnable, and marks the icon as trusted. |
The one command
Run from inside the project folder on the Pi:
python3 -m pip install --break-system-packages --no-index --find-links=offline_packages pyserial numpy matplotlib pyubx2 pynmeagps pyrtcm && chmod +x record.sh run_vna_live.sh install_launcher.sh && ./install_launcher.sh && python3 -c "import serial, numpy, matplotlib, pyubx2; print('READY')"
--no-index --find-links=offline_packages tells pip to install only from the local folder and never look online. The last part checks that every library imports and prints READY.
Status: the package files and the command are built for the Pi's Python 3.13. A successful run on the Pi isn't confirmed yet.
What's next
- Find the GPS module's serial speed. Try each common baud rate until clean messages appear, then set the code to match. Nothing on the GPS side can be tested until the module and the Pi agree on a speed.
- First position-tagged sweeps. Walk a known route with Record running, and check that every file holds a fix with its satellite count, accuracy and fix type.
- Save the GPS's own time in every file. The driver already reads the time stamp inside each GPS message, but doesn't save it yet. Saving it next to the Pi's clock would measure the serial delay in Note 7.3.
- Add calibration. Measure a short, an open and a 50 Ω load at the analyzer's connector, and correct every sweep with them, so the files hold calibrated values instead of raw ratios.
- An analysis tool for a folder of captures. Read every
capture_*.s2pin a folder and produce one table (time, latitude, longitude, fix type, and \(|S_{11}|\) and \(|S_{21}|\) at chosen frequencies), plus a map. Recording is now easy. This is the step that makes the analysis easy too. - Test more analyzers. The drivers should also handle the NanoVNA-H4, NanoVNA-V2 and LiteVNA-64, but we haven't tried them yet.
Join the conversation
We'd rather be corrected early than be wrong in public later. If you use NanoVNAs or GPS in the field, know a better way to do any of this, or have hit the same problems, send it. Students, hams, engineers and skeptics are all welcome.
Questions we'd like help with
- What would you want out of a folder of position-tagged sweeps: a map, a table, something else?
- Has anyone else seen a NanoVNA-F V2 return a partial sweep padded with zeros? Is there firmware that fixes it?
- Which other NanoVNA models should we test?
- How do you keep a VNA calibration valid in the field, when the cables flex as it moves?
- What's the most reliable way to find a u-blox receiver's serial speed?
Message sent. Thank you. If you left an email, we'll reply there.
You can also email Hexapole6@proton.me or Eodymy1@proton.me, or comment on any video on our YouTube channel.