# VirtualPSU

## class VirtualPSU( num_channels: int = DEFAULT_NUM_CHANNELS, load_resistance: float | Mapping[int, float] = DEFAULT_LOAD_RESISTANCE, )[source]

Bases: [`PSUDriverBase`](https://dev.nominal.io/instro/ref/instruments/instro.psu.PSUDriverBase.md#instro.psu.PSUDriverBase "instro.psu.psu.PSUDriverBase")

PSU simulated in-process: no transport, server, or hardware.

Each channel drives its own resistive load. With the output on, a channel holds its voltage
setpoint (constant voltage) until the load would draw more than the current limit, then
holds the current limit (constant current). Readings carry 0.5% noise, the SCPI simulator’s
level. The current limit starts at the channel maximum (10 A), so setting a voltage and
enabling the output is enough to see it.

As on the SCPI simulator, voltages must lie within 0 to 60 V and currents within 0 to 10 A,
or the setter raises `ValueError`. Unlike it, a setpoint may sit above its protection level,
which is how a virtual channel trips: there is no external source to push the output past
its setpoint.

Enabled overvoltage or overcurrent protection trips when the output exceeds its level,
latching the output off until [`clear_protection`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.clear_protection "instro.psu.drivers.virtual.VirtualPSU.clear_protection") and a new [`output_enable`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.output_enable "instro.psu.drivers.virtual.VirtualPSU.output_enable"); `output_enable`
alone also clears the latch, as on the SCPI simulator. As there, protection is checked after
every change that can move the output (setpoints, protection settings, output enable, and
the load), so a fault trips when it happens, and readings never change state. Remote sense
and the overvoltage protection delay are stored and have no effect on readings. To exercise
the VISA transport as well, use `SimulatedPSU` with the bundled SCPI simulator.

Create a virtual PSU.

Parameters:
:   - **num_channels** ([*int*](https://docs.python.org/3/builtins/functions.html#int "(in Python v3.15)"))

      Number of output channels, numbered from 1. Pass the same count
      to `InstroPSU`; a channel above it raises `ValueError`.
    - **load_resistance** ([*float*](https://docs.python.org/3/builtins/functions.html#float "(in Python v3.15)") *|* *Mapping**[*[*int*](https://docs.python.org/3/builtins/functions.html#int "(in Python v3.15)")*,* [*float*](https://docs.python.org/3/builtins/functions.html#float "(in Python v3.15)")*]*)

      Resistance of each channel’s load, in
      ohms: one value for every channel, or a mapping from channel to value, with
      channels left out at 1000 ohms. `0` is a short and `math.inf` an open circuit.
      Change it at any time with [`set_load_resistance`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_load_resistance "instro.psu.drivers.virtual.VirtualPSU.set_load_resistance") to move a channel between
      constant voltage and constant current.

Raises:
:   [**ValueError**](https://docs.python.org/3/builtins/exceptions.html#ValueError "(in Python v3.15)") – `num_channels` is less than 1, or `load_resistance` is negative or
    names a channel that does not exist.

Example:

```
from instro.psu import InstroPSU
from instro.psu.drivers import VirtualPSU

driver = VirtualPSU(num_channels=2, load_resistance={1: 10.0, 2: 1.0})
with InstroPSU(name="psu", driver=driver, num_channels=2) as psu:
    for channel in (1, 2):
        psu.apply(current_limit=1.0, voltage=5.0, enable=True, channel=channel)
    print(psu.get_operating_mode(channel=1).latest)  # CV: 10 ohms draws 0.5 A
    print(psu.get_operating_mode(channel=2).latest)  # CC: 1 ohm would draw 5 A
    driver.set_load_resistance(100.0, channel=2)
    print(psu.get_operating_mode(channel=2).latest)  # CV
```

Methods

| [`clear_protection`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.clear_protection "instro.psu.drivers.virtual.VirtualPSU.clear_protection") | Clear every latched protection trip on `channel`. |
| --- | --- |
| [`close`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.close "instro.psu.drivers.virtual.VirtualPSU.close") | Nothing to disconnect. |
| [`get_current`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_current "instro.psu.drivers.virtual.VirtualPSU.get_current") | Query the measured output current (amperes) on `channel`. |
| [`get_current_setpoint`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_current_setpoint "instro.psu.drivers.virtual.VirtualPSU.get_current_setpoint") | Query the configured current-limit setpoint (amperes) on `channel`. |
| [`get_load_resistance`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_load_resistance "instro.psu.drivers.virtual.VirtualPSU.get_load_resistance") | Return the load resistance on `channel`, in ohms. |
| [`get_operating_mode`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_operating_mode "instro.psu.drivers.virtual.VirtualPSU.get_operating_mode") | Query whether `channel` is regulating in constant voltage, constant current, unregulated, or off. |
| [`get_output_status`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_output_status "instro.psu.drivers.virtual.VirtualPSU.get_output_status") | Query whether the output on `channel` is enabled. |
| [`get_overcurrent_protection_enabled`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overcurrent_protection_enabled "instro.psu.drivers.virtual.VirtualPSU.get_overcurrent_protection_enabled") | Query whether overcurrent protection is enabled on `channel`. |
| [`get_overcurrent_protection_level`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overcurrent_protection_level "instro.psu.drivers.virtual.VirtualPSU.get_overcurrent_protection_level") | Query the overcurrent protection threshold (amperes) on `channel`. |
| [`get_overcurrent_protection_tripped`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overcurrent_protection_tripped "instro.psu.drivers.virtual.VirtualPSU.get_overcurrent_protection_tripped") | Query whether overcurrent protection has tripped on `channel` and not been cleared. |
| [`get_overvoltage_protection_delay`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_delay "instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_delay") | Query the overvoltage protection trip delay (seconds) on `channel`. |
| [`get_overvoltage_protection_enabled`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_enabled "instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_enabled") | Query whether overvoltage protection is enabled on `channel`. |
| [`get_overvoltage_protection_level`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_level "instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_level") | Query the overvoltage protection threshold (volts) on `channel`. |
| [`get_overvoltage_protection_tripped`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_tripped "instro.psu.drivers.virtual.VirtualPSU.get_overvoltage_protection_tripped") | Query whether overvoltage protection has tripped on `channel` and not been cleared. |
| [`get_remote_sense_enabled`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_remote_sense_enabled "instro.psu.drivers.virtual.VirtualPSU.get_remote_sense_enabled") | Query whether remote sense is enabled on `channel`. |
| [`get_voltage`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_voltage "instro.psu.drivers.virtual.VirtualPSU.get_voltage") | Query the measured output voltage (volts) on `channel`. |
| [`get_voltage_setpoint`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.get_voltage_setpoint "instro.psu.drivers.virtual.VirtualPSU.get_voltage_setpoint") | Query the configured voltage setpoint (volts) on `channel`. |
| [`open`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.open "instro.psu.drivers.virtual.VirtualPSU.open") | Nothing to connect to. |
| [`output_enable`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.output_enable "instro.psu.drivers.virtual.VirtualPSU.output_enable") | Enable or disable the output on `channel`. |
| [`set_current_limit`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_current_limit "instro.psu.drivers.virtual.VirtualPSU.set_current_limit") | Set the current limit (amperes) on `channel`. |
| [`set_load_resistance`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_load_resistance "instro.psu.drivers.virtual.VirtualPSU.set_load_resistance") | Set the load on `channel`, or on every channel when `channel` is `None`. |
| [`set_overcurrent_protection_enabled`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_overcurrent_protection_enabled "instro.psu.drivers.virtual.VirtualPSU.set_overcurrent_protection_enabled") | Enable or disable overcurrent protection on `channel`. |
| [`set_overcurrent_protection_level`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_overcurrent_protection_level "instro.psu.drivers.virtual.VirtualPSU.set_overcurrent_protection_level") | Set the overcurrent protection threshold (amperes) on `channel`. |
| [`set_overvoltage_protection_delay`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_overvoltage_protection_delay "instro.psu.drivers.virtual.VirtualPSU.set_overvoltage_protection_delay") | Stored; protection trips without delay. |
| [`set_overvoltage_protection_enabled`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_overvoltage_protection_enabled "instro.psu.drivers.virtual.VirtualPSU.set_overvoltage_protection_enabled") | Enable or disable overvoltage protection on `channel`. |
| [`set_overvoltage_protection_level`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_overvoltage_protection_level "instro.psu.drivers.virtual.VirtualPSU.set_overvoltage_protection_level") | Set the overvoltage protection threshold (volts) on `channel`. |
| [`set_remote_sense_enabled`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_remote_sense_enabled "instro.psu.drivers.virtual.VirtualPSU.set_remote_sense_enabled") | Stored; the virtual load has no lead resistance, so readings are unchanged. |
| [`set_voltage`](https://dev.nominal.io/instro/ref/instruments/instro.psu.drivers.virtual.VirtualPSU.md#instro.psu.drivers.virtual.VirtualPSU.set_voltage "instro.psu.drivers.virtual.VirtualPSU.set_voltage") | Set the output voltage (volts) on `channel`. |

### set_load_resistance( resistance: float, channel: int | None = None, ) → None[source]

Set the load on `channel`, or on every channel when `channel` is `None`.

Parameters:
:   - **resistance** ([*float*](https://docs.python.org/3/builtins/functions.html#float "(in Python v3.15)"))

      Load resistance in ohms. `0` is a short and `math.inf` an
      open circuit.
    - **channel** ([*int*](https://docs.python.org/3/builtins/functions.html#int "(in Python v3.15)") *|* *None*)

      Target channel (1-indexed), or `None` for every channel.

Raises:
:   [**ValueError**](https://docs.python.org/3/builtins/exceptions.html#ValueError "(in Python v3.15)") – `resistance` is negative, or `channel` does not exist.

### get_load_resistance(channel: int) → float[source]

Return the load resistance on `channel`, in ohms.

### open() → None[source]

Nothing to connect to.

### close() → None[source]

Nothing to disconnect.

### set_voltage(voltage: float, channel: int) → None[source]

Set the output voltage (volts) on `channel`.

### get_voltage(channel: int) → float[source]

Query the measured output voltage (volts) on `channel`. Output may vary from voltage setpoint outside of constant voltage mode.

### set_current_limit(current_limit: float, channel: int) → None[source]

Set the current limit (amperes) on `channel`.

### get_current(channel: int) → float[source]

Query the measured output current (amperes) on `channel`. Output may vary from current-limit setpoint outside of constant current mode.

### output_enable(enable: bool, channel: int) → None[source]

Enable or disable the output on `channel`.

### get_output_status(channel: int) → bool[source]

Query whether the output on `channel` is enabled.

### get_voltage_setpoint(channel: int) → float[source]

Query the configured voltage setpoint (volts) on `channel`. Output may vary from actual measured voltage outside of constant voltage mode.

### get_current_setpoint(channel: int) → float[source]

Query the configured current-limit setpoint (amperes) on `channel`. Output may vary from actual measured current outside of constant current mode.

### get_operating_mode( channel: int, ) → OperatingMode[source]

Query whether `channel` is regulating in constant voltage, constant current, unregulated, or off.

### set_overvoltage_protection_level( voltage: float, channel: int, ) → None[source]

Set the overvoltage protection threshold (volts) on `channel`.

### get_overvoltage_protection_level(channel: int) → float[source]

Query the overvoltage protection threshold (volts) on `channel`.

### set_overvoltage_protection_enabled( enabled: bool, channel: int, ) → None[source]

Enable or disable overvoltage protection on `channel`.

### get_overvoltage_protection_enabled(channel: int) → bool[source]

Query whether overvoltage protection is enabled on `channel`.

### set_overvoltage_protection_delay( delay: float, channel: int, ) → None[source]

Stored; protection trips without delay.

### get_overvoltage_protection_delay(channel: int) → float[source]

Query the overvoltage protection trip delay (seconds) on `channel`.

### set_overcurrent_protection_level( current: float, channel: int, ) → None[source]

Set the overcurrent protection threshold (amperes) on `channel`.

### get_overcurrent_protection_level(channel: int) → float[source]

Query the overcurrent protection threshold (amperes) on `channel`.

### set_overcurrent_protection_enabled( enabled: bool, channel: int, ) → None[source]

Enable or disable overcurrent protection on `channel`.

### get_overcurrent_protection_enabled(channel: int) → bool[source]

Query whether overcurrent protection is enabled on `channel`.

### clear_protection(channel: int) → None[source]

Clear every latched protection trip on `channel`. The output stays off until re-enabled.

### get_overvoltage_protection_tripped(channel: int) → bool[source]

Query whether overvoltage protection has tripped on `channel` and not been cleared.

### get_overcurrent_protection_tripped(channel: int) → bool[source]

Query whether overcurrent protection has tripped on `channel` and not been cleared.

### set_remote_sense_enabled(enabled: bool, channel: int) → None[source]

Stored; the virtual load has no lead resistance, so readings are unchanged.

### get_remote_sense_enabled(channel: int) → bool[source]

Query whether remote sense is enabled on `channel`.
