Skip to main content

PSU simulator

The PSU simulator is a local SCPI server for development, tests, and demos. It listens on a TCP socket, exposes a programmable power-supply command set, and includes a terminal UI for editing channel loads, probe resistance, and channel limits while your code is running.

Quickstart

Start the simulator in one terminal:
python -m instro.psu.scpi_sim_server
It binds to 127.0.0.1:5025 by default. If you are working from a source checkout, run the same command through uv:
uv run python -m instro.psu.scpi_sim_server
Connect from another terminal or script with the SimulatedPSU driver. This small Python client opens an InstroPSU, configures channel 1, and reads voltage and current measurements:
from instro.psu import InstroPSU
from instro.psu.drivers import SimulatedPSU


with InstroPSU(
    name="bench_psu",
    driver=SimulatedPSU("TCPIP0::127.0.0.1::5025::SOCKET"),
    num_channels=2,
) as psu:
    psu.set_voltage(5.0, channel=1)
    psu.set_current_limit(1.0, channel=1)
    psu.output_enable(True, channel=1)

    voltage = psu.get_voltage(channel=1)
    current = psu.get_current(channel=1)
    print(f"V: {voltage.latest:.3f} V")
    print(f"I: {current.latest:.3f} A")

    psu.output_enable(False, channel=1)
Use CLI flags to change the bind address, port, or initial channel count:
python -m instro.psu.scpi_sim_server --host 127.0.0.1 --port 5025 --channels 2

Usage

The simulator runs a terminal UI while the TCP server listens in the background. The UI is organized by panel header. PSU simulator terminal UI showing the PSU panel, channel panels, and SCPI log Filled labels are selectable actions. Use the arrow keys to move between controls. Focused actions use a light highlight. Press Enter to select an action, Escape to close an edit prompt, and q to quit.

PSU

The ⟢ NOMINAL PSU panel shows the simulator identity and VISA resource string. Use the resource string when driver code connects to the simulator.

Channel

Each CHANNEL panel shows the live state for one output. The panel is split into status, voltage, and current sections.
HeaderFunctionality
STATUSShows output mode, output state, sense mode, and protection trips. Select REMOVE to delete the channel from the simulator.
VOLTAGEShows terminal voltage, programmed voltage, voltage limit, OVP state, and OVP level. Select V LIMIT to edit the channel voltage ceiling.
CURRENTShows output current, programmed current limit, current limit, OCP state, and OCP level. Select I LIMIT to edit the channel current ceiling.
Changing V LIMIT or I LIMIT runs *RST. The output turns off, programmed voltage and current return to zero, protection state turns off, and OVP/OCP levels return to the configured V/I limits.

Probe

The PROBE panel shows sense lead resistance. Select PROBE R to edit the probe resistance in ohms.

Load

The LOAD panel shows the external load model. Select R to edit load resistance in ohms. Select EMF to edit the series electromotive force in volts.

+ channel

The + CHANNEL panel adds a new output channel with the next available channel ID.

SCPI log

The SCPI LOG panel records incoming commands, responses, and queued errors. It is read-only.

Programming guide

Brackets mark optional SCPI path components. For example, [SOURce:]VOLTage[:LEVel] accepts VOLT, VOLT:LEV, SOUR:VOLT, and SOUR:VOLT:LEV. Angle brackets mark command arguments. They are notation only; do not include the angle brackets in the command.
  • <NRf+> is a positive flexible numeric value, such as 0, 1.25, or 1e-3.
  • <literal|literal> is one literal value from the listed options.
The pipe character (|) means OR. For example, <LOC|REM> accepts LOC or REM, and <NRf+|MIN|MAX> accepts one numeric value, MIN, or MAX. Do not send the pipe character in the command. MIN maps to 0. MAX maps to V LIMIT for voltage and OVP commands, and I LIMIT for current and OCP commands. Do not send MIN or MAX to queries.

Defaults and reset

On startup and after *RST, each channel uses the reset operating state:
SettingReset value
Programmed voltage0
Current limit0
Output stateOFF
OVP stateOFF
OCP stateOFF
OVP levelMAX
OCP levelMAX
*RST preserves simulator configuration, including channel count, channel IDs, load resistance, series EMF, probe resistance, sense mode, and configured channel limits.

Error queue

Errors are queued and returned one at a time by SYSTem:ERRor?. The simulator can emit these error codes:
CodeMessageCause
0No errorThe queue is empty
-108Parameter not allowedA query received an argument
-109Missing parameterA command was sent without a required argument
-113Undefined headerThe command header is not supported
-114Header suffix out of rangeThe command targets a channel that does not exist
-141Invalid character dataA numeric argument could not be parsed
-222Data out of rangeA numeric input is outside its accepted range
-224Illegal parameter valueA literal argument is not accepted for that command
301PV Above OVPProgrammed voltage is above the OVP level
303PC Above OCPCurrent limit is above the OCP level
304OVP Below PVOVP level is below programmed voltage
305OCP Below PCOCP level is below current limit
323Overcurrent protection trippedOCP tripped while enabled
324Overvoltage protection trippedOVP tripped while enabled

Common commands

*IDN?
Query simulator identityResponse: String
*RST
Reset channel operating state and clear errorsResponse: None
*CLS
Clear the error queueResponse: None

MEASure subsystem

MEASure:CURRent?
Measure output currentResponse: Number
MEASure:VOLTage?
Measure output voltageResponse: Number

OUTPut subsystem

OUTPut[:STATe] <0|1|OFF|ON>
Enable or disable outputResponse: None
OUTPut[:STATe]?
Query output stateResponse: 0 or 1
OUTPut:PROTection:CLEar
Clear latched OVP and OCP faultsResponse: None
OUTPut:PROTection:TRIPped?
Query latched OVP or OCP fault stateResponse: 0 or 1

SOURce subsystem

[SOURce:]CURRent[:LEVel][:IMMediate][:AMPLitude] <NRf+|MIN|MAX>
Set current limitResponse: None
[SOURce:]CURRent[:LEVel][:IMMediate][:AMPLitude]?
Query current limitResponse: Number
[SOURce:]CURRent:PROTection[:LEVel] <NRf+|MIN|MAX>
Set OCP levelResponse: None
[SOURce:]CURRent:PROTection[:LEVel]?
Query OCP levelResponse: Number
[SOURce:]CURRent:PROTection:STATe <0|1|OFF|ON>
Enable or disable OCPResponse: None
[SOURce:]CURRent:PROTection:STATe?
Query OCP stateResponse: 0 or 1
[SOURce:]VOLTage[:LEVel][:IMMediate][:AMPLitude] <NRf+|MIN|MAX>
Set programmed voltageResponse: None
[SOURce:]VOLTage[:LEVel][:IMMediate][:AMPLitude]?
Query programmed voltageResponse: Number
[SOURce:]VOLTage:PROTection[:LEVel] <NRf+|MIN|MAX>
Set OVP levelResponse: None
[SOURce:]VOLTage:PROTection[:LEVel]?
Query OVP levelResponse: Number
[SOURce:]VOLTage:PROTection:STATe <0|1|OFF|ON>
Enable or disable OVPResponse: None
[SOURce:]VOLTage:PROTection:STATe?
Query OVP stateResponse: 0 or 1

SYSTem subsystem

SYSTem:ERRor?
Pop one error from the error queueResponse: code,“message”
SYSTem:SENSe[:STATe] <LOC|REM>
Select local or remote senseResponse: None
SYSTem:SENSe[:STATe]?
Query sense modeResponse: LOC or REM