OpenChoice is free, Tektronix-only, and does screen capture and data transfer. Here is what it covers, the point at which every user outgrows it, and the five alternatives.

Tektronix OpenChoice is a free set of desktop utilities for getting data and screen images off Tektronix oscilloscopes. It handles connection over USB or LAN, screen capture into documents, waveform transfer into Excel, and a Talker Listener console for sending raw commands.
It does that job adequately and it costs nothing. It is also single-vendor, barely developed, and stops precisely where validation work starts. This post covers what it does, the specific point at which everyone outgrows it, and the five alternatives.
| Component | What it does |
|---|---|
| OpenChoice Desktop | Connect, screen capture, waveform transfer, save to file |
| Talker Listener | Send raw SCPI commands and see responses, useful for debugging |
| Office Toolkit | Paste scope images and data directly into Word and Excel |
| IVI and VISA drivers | The underlying connectivity layer |
For an engineer who needs a scope screenshot in a report, this is genuinely the fastest route. Connect, capture, paste. Done.
The wall is always the same, and it arrives the first time the measurement needs a condition to be set before it is taken.
"Capture the ripple on the 1.8 V rail at 500 mA load, at 25 and 85 degrees, at three input voltages."
That is nine captures, and OpenChoice can help with none of the setup. It cannot command the power supply. It cannot command the electronic load. It cannot step the conditions, wait for settling, check a limit, or write a verdict. It captures whatever is on the screen when you press the button.
So the workflow becomes: a human sets the supply, sets the load, waits, presses capture in OpenChoice, renames the file, and repeats nine times. Then correlates them in Excel.
That is the point to leave.
Free and open source, and Tektronix's own supported Python package. This is the intended successor for automation and it is considerably better than OpenChoice's scripting.
from tm_devices import DeviceManager
with DeviceManager() as dm:
scope = dm.add_scope("192.168.1.50")
scope.commands.horizontal.scale.write(1e-3)
scope.commands.ch[1].scale.write(0.5)
scope.commands.trigger.a.edge.source.write("CH1")
scope.commands.acquire.state.write("RUN")
vpp = scope.commands.measurement.meas[1].results.currentacq.mean.query()Good for: all-Tektronix benches. Typed command access, device discovery, and proper error handling.
Gives up: other vendors. It is a Tektronix library and does not pretend otherwise.
Verdict: if your bench is Tektronix, use this instead of OpenChoice, today. It is strictly better and equally free.
Covers the whole sequence rather than the capture. You add the scope, supply, and load by model and VISA address, describe the measurement in plain English, and the agent generates the automation, runs the nine-point matrix, and produces the report with pass and fail per point.
Good for: the exact scenario that breaks OpenChoice, which is a measurement with conditions.
Gives up: the instant screenshot-into-Word workflow, which OpenChoice does well and which remains a reasonable reason to keep it installed.
Verdict: the answer when the scope is one instrument in a test, not the test itself.
Free and vendor-neutral. The general answer.
import pyvisa
rm = pyvisa.ResourceManager()
scope = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
psu = rm.open_resource("TCPIP0::192.168.1.42::inst0::INSTR")
for vin in (3.0, 3.3, 3.6):
psu.write(f"VOLT {vin}")
psu.write("OUTP ON")
scope.write("ACQUIRE:STATE RUN")
scope.write("MEASUREMENT:IMMED:TYPE PK2PK")
scope.write("MEASUREMENT:IMMED:SOURCE CH1")
ripple = float(scope.query("MEASUREMENT:IMMED:VALUE?"))
print(f"VIN {vin} V -> ripple {ripple*1000:.1f} mVpp "
f"{'PASS' if ripple < 0.05 else 'FAIL'}")
psu.write("OUTP OFF")Good for: exactly the case OpenChoice cannot do. The supply and the scope in one loop, with a verdict.
Gives up: requires Python. That is the whole cost.
Verdict: the default. See the PyVISA tutorial and the Tektronix Python guide.
No-code, application-based, and it does drive some third-party instruments. Mentioned because it is the closest thing to "OpenChoice but better and cross-vendor", though it leans heavily toward Keysight hardware.
Good for: engineers who want a UI rather than code, on a Keysight-leaning bench.
Gives up: money, and full Tektronix support. See Keysight BenchVue alternatives.
Verdict: not really an OpenChoice replacement for a Tektronix bench. Listed for completeness.
Free with Pico hardware, and genuinely good software. Worth knowing about because for some measurements a USB scope with good software beats a benchtop scope with poor software.
Good for: teams buying new, where the software quality can influence the hardware choice.
Gives up: it needs Pico hardware. It will not help with the Tektronix scope you already own.
Verdict: relevant at purchase time, not at migration time.
| OpenChoice | tm_devices | PyVISA | BenchVue | TestFlow | |
|---|---|---|---|---|---|
| Cost | Free | Free | Free | Per app | Free version, then paid |
| Tektronix support | Native | Native | Yes | Limited | Yes |
| Other vendors | No | No | Yes | Some | Yes |
| Screen capture to Word | Excellent | Via script | Via script | Yes | Report export |
| Sequencing | No | You code it | You code it | Some apps | Generated |
| Drives power supplies | No | Some | Yes | Yes | Yes |
| Pass and fail limits | No | You code it | You code it | Some apps | Yes |
| Requires programming | No | Yes | Yes | No | No |
There is no reason to uninstall OpenChoice. It costs nothing and it is the fastest path to a screenshot.
The practical arrangement most labs land on:
The mistake is treating OpenChoice as the automation story. It was never that, and Tektronix's own investment in tm_devices says so.
Most OpenChoice usage is one workflow: capture the screen, paste into a report. Replacing that with code is straightforward and worth doing, because the captured image then carries the conditions that produced it.
import pyvisa
rm = pyvisa.ResourceManager()
scope = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
scope.timeout = 20000
scope.write("SAVE:IMAGE:FILEFORMAT PNG")
scope.write("HARDCOPY START")
raw = scope.read_raw()
name = f"ripple_vin3v3_load500ma_25c.png"
with open(name, "wb") as f:
f.write(raw)
print(f"saved {name} ({len(raw)} bytes)")The gain is not the automation, it is the filename. A screenshot called tek0003.png is worthless in six months. One called ripple_vin3v3_load500ma_25c.png is evidence, and generating it from the loop that set those conditions means it can never be mislabelled.
Extend the same idea to the report: capture the image, record the numeric measurements alongside it, and write both into the run record. That is the difference between a folder of screenshots and a validation result.
Not everything needs automating, and it is worth saying where the effort does not pay back.
The rule of thumb: automate at the third repetition, not the first. Automating a measurement you will take twice is a hobby, not engineering. The reason OpenChoice frustrates people is not that it is a bad tool, it is that it gets used well past the point where the third repetition arrived.
The other thing people use OpenChoice for is pulling the waveform record into Excel. Doing it in code is not much harder and gives you the scaling factors, which the OpenChoice export can lose.
scope.write("DATA:SOURCE CH1")
scope.write("DATA:ENC RIBINARY")
scope.write("DATA:WIDTH 2")
scope.write("DATA:START 1")
scope.write("DATA:STOP 100000")
ymult = float(scope.query("WFMOUTPRE:YMULT?"))
yoff = float(scope.query("WFMOUTPRE:YOFF?"))
yzero = float(scope.query("WFMOUTPRE:YZERO?"))
xincr = float(scope.query("WFMOUTPRE:XINCR?"))
raw = scope.query_binary_values("CURVE?", datatype="h", container=list)
volts = [(point - yoff) * ymult + yzero for point in raw]
times = [i * xincr for i in range(len(volts))]The four scaling queries are the part that matters. Raw curve data is in digitiser levels, not volts, and applying YMULT, YOFF, and YZERO is what converts it. Skipping that step is the most common reason exported waveforms look like nonsense.
OpenChoice-era workflows tend to share the same three manual steps. Each has a direct automated equivalent that takes under an hour to build, and replacing them in this order gives the fastest return.
| Manual habit | Automated equivalent | Effort |
|---|---|---|
| Save screenshot to a USB stick | HARDCopy STARt over LAN, straight to a dated folder | 20 minutes |
| Read a measurement off the screen and type it into Excel | MEASUrement:IMMed:VALue? into a CSV row | 30 minutes |
| Export CSV per capture, then combine by hand | One script that loops the sweep and writes one file | 2 hours |
The third one is where the actual time goes, and it is also where transcription errors live. A characterisation run with twenty operating points is twenty chances to type a number into the wrong cell.
The single highest-return replacement, because it removes a walk to the bench.
import datetime, pathlib
scope.write("HARDCopy:PORT ETHERnet")
scope.write("HARDCopy:FORMat PNG")
scope.write("HARDCopy:LAYout LANdscape")
scope.write("HARDCopy:PALEtte INKSaver") # white background, prints properly
png = scope.query_binary_values("HARDCopy STARt", datatype="B", container=bytes)
stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
out = pathlib.Path("captures") / f"scope-{stamp}.png"
out.parent.mkdir(exist_ok=True)
out.write_bytes(png)
print(f"saved {out}")INKSaver is worth setting: the default palette is the scope's dark screen, which looks poor in a report and uses a lot of toner. The timestamped filename is the other half of the point, since the naming problem is what makes a folder of screenshots unusable six months later.
Older TDS-series scopes use HARDCopy:PORT GPIb and a slightly different format list, so check HARDCopy? on your model before assuming the block above transfers.
The upgrade from the screenshot habit. Same instrument, same session, but the output is a row of values you can plot, diff, and compare against limits.
import csv
MEASUREMENTS = [("PK2PK", "CH1"), ("MEAN", "CH1"), ("FREQuency", "CH1"), ("RISe", "CH1")]
def read_measurements(scope):
row = {}
for kind, source in MEASUREMENTS:
scope.write(f"MEASUrement:IMMed:TYPe {kind}")
scope.write(f"MEASUrement:IMMed:SOUrce {source}")
row[f"{source}_{kind.lower()}"] = float(scope.query("MEASUrement:IMMed:VALue?"))
return row
with open("sweep.csv", "w", newline="") as fh:
writer = None
for v_in in (10.8, 12.0, 13.2):
psu.write(f":SOUR:VOLT {v_in}")
time.sleep(0.5)
scope.write("ACQuire:STOPAfter SEQuence")
scope.write("ACQuire:STATE ON")
scope.query("*OPC?") # block until the acquisition completes
row = {"vin": v_in, **read_measurements(scope)}
if writer is None:
writer = csv.DictWriter(fh, fieldnames=list(row))
writer.writeheader()
writer.writerow(row)The *OPC? query is the important line. Without it the script reads measurements from whatever the scope had on screen before the new acquisition finished, which produces plausible numbers that are silently one operating point stale.
scope1.png through scope40.png is not a dataset.OpenChoice ends where real validation begins, at the point where the scope is one instrument in a sequence rather than the only thing on the bench.
Connect your instruments. Pick the manufacturer and model, paste the VISA address (USB, LAN, GPIB, or serial), and the agent knows what is on your bench. No bench yet? Use a placeholder address, build the full automation, and swap in the real address when you are in the lab.
Tell the agent what to test, in plain English. For example, "run a VI sweep from 1 to 10 V in 1 V steps at 0.5 A load current," or "suggest the tests for a power-management device."
The agent builds the complete workflow in seconds. Instrument-aware automation appears on the canvas, with the generated scripts visible in a code panel you can inspect and edit.
Run it in your lab. Click Run and the status panel streams results step by step, with measured values inline (VOUT = 3.301 V, asserted 3.2 to 3.4 V, PASS). One click exports a structured PDF report, or the raw results as CSV.


The step-by-step walkthrough, VISA address formats, and Test Planner prompts are all in the TestFlow product guide.
A free set of desktop utilities from Tektronix for connecting to their oscilloscopes over USB or LAN, capturing screen images, transferring waveform data, and pasting results into Word or Excel.
OpenChoice Desktop is still available as a free download but receives little development. Tektronix has shifted its Python effort to the tm_devices library, which is the better-supported route for automation.
No. It is built for Tektronix hardware. For a mixed-vendor bench you need a vendor-neutral layer such as PyVISA or a platform that abstracts across vendors.
Python with PyVISA for general control, or Tektronix's own tm_devices library if your bench is all Tektronix. Both are free and both do far more than OpenChoice.
Not really. It is a capture and transfer tool with limited scripting via its Talker Listener utility. Anything that involves stepping conditions, checking limits, and producing a verdict needs a different tool.
Tektronix's supported open-source Python package for controlling their instruments. It handles connection, command sending, and device-specific behaviour, and is the recommended automation route for Tektronix hardware.
Connect your instruments, describe a test in plain English, and TestFlow builds and runs it in minutes.
A new way for testing, from specs to automated sequences, capture clean data, and accelerate your validation cycle.