Skip to content

Commit

Permalink
Updated output voltage with custom visa dmm driver (#447)
Browse files Browse the repository at this point in the history
* Updated output voltage with custom visa dmm driver

* Fixed lint errors
  • Loading branch information
Avinash2Suresh authored Oct 13, 2023
1 parent 8a05e88 commit 8393c2d
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 203 deletions.
68 changes: 0 additions & 68 deletions examples/output_voltage_measurement/NIInstrumentSimulatorV2_0.yaml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<NIDCPowerInstrument name="DCPower1" numberOfChannels="4">
<ChannelGroup name="CommonDCPowerChannelGroup" />
</NIDCPowerInstrument>
<Instrument name="GPIB0::3::INSTR" instrumentTypeId="DigitalMultimeterSimulator">
<Instrument name="GPIB0::3::INSTR" instrumentTypeId="VisaDmm">
<Channel id="0" />
</Instrument>
</Instruments>
Expand Down
25 changes: 14 additions & 11 deletions examples/output_voltage_measurement/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Output Voltage Measurement

This is a MeasurementLink example that sources DC voltage as input to the DUT with an NI SMU and measures the DUT output with DMM using NI-VISA.
This is a MeasurementLink example that sources DC voltage as input to the DUT with an NI SMU and measures the DUT output with a DMM that supports SCPI commands using NI-VISA.

### Features

Expand All @@ -27,21 +27,24 @@ This is a MeasurementLink example that sources DC voltage as input to the DUT wi
- NI-VISA
- Optional: NI Instrument Simulator software

Note: there is no Python instrument driver for the NI Instrument Simulator, so
this example directly performs low-level, device-specific commands and queries.
> **Note:**
>
> This example uses the custom instrument driver `_visa_dmm.py` to perform the device-specific commands and queries.
### Required Hardware

By default, this example does not require hardware; it uses a simulated instrument and PyVISA-sim to simulate NI-DCPower and NI-VISA DMM instruments in software. [`NIInstrumentSimulatorV2_0.yaml`](./NIInstrumentSimulatorV2_0.yaml) defines the behavior of the simulated NI-VISA DMM instrument.
By default, this example does not require hardware; it uses a simulated instrument and PyVISA-sim to simulate NI-DCPower and NI-VISA DMM instruments in software. [`_visa_dmm_sim.yaml`](./_visa_dmm_sim.yaml) defines the behavior of the simulated NI-VISA DMM instrument.

This example requires an NI SMU that is supported by NI-DCPower (e.g. PXIe-4141).
Supported instrument models:
- NI Instrument Simulator v2.0
- HP/Agilent/Keysight 34401A DMM

By default, this example uses simulated instruments. To use physical instruments, edit
`_constants.py` to specify `USE_SIMULATION = False`.

To use NI Instrument Simulator hardware:

- Connect the NI Instrument Simulator over GPIB or serial.
To use a physical instrument:
- This example requires an NI SMU that is supported by NI-DCPower (e.g. PXIe-4141).
- By default, this example uses simulated instruments. To use physical instruments, edit
`_constants.py` to specify `USE_SIMULATION = False`.
- Connect the instrument to a supported interface, such as GPIB or serial.
- By default, the pin map included with this example uses the resource name
`GPIB0::3::INSTR`, which matches the NI Instrument Simulator's factory default
settings when connected via GPIB.
Expand All @@ -53,4 +56,4 @@ To use NI Instrument Simulator hardware:
the NI Instrument Simulator software.

To use a 3rd party DMM, such as a Keysight 34401A:
- Verify the driver specific commands in `_visa_helpers.py` and update them if required.
- Verify the driver specific commands in `_visa_dmm.py` and update them if required.
145 changes: 145 additions & 0 deletions examples/output_voltage_measurement/_visa_dmm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""Custom instrument driver for MeasurementLink NI-VISA DMM examples."""
from __future__ import annotations

import pathlib
import sys
from enum import Enum
from types import TracebackType
from typing import (
TYPE_CHECKING,
Optional,
Type,
)

import pyvisa
import pyvisa.resources
import pyvisa.typing


if TYPE_CHECKING:
if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self


# Pin map instrument type constant for VISA DMM
INSTRUMENT_TYPE_VISA_DMM = "VisaDmm"

_SIMULATION_YAML_PATH = pathlib.Path(__file__).resolve().parent / "_visa_dmm_sim.yaml"

_RESOLUTION_DIGITS_TO_VALUE = {"3.5": 0.001, "4.5": 0.0001, "5.5": 1e-5, "6.5": 1e-6}

# Supported NI-VISA DMM instrument IDs, both real and simulated, can be added here
_SUPPORTED_INSTRUMENT_IDS = [
# Keysight/Agilent/HP 34401A
"34401",
"34410",
"34411",
"L4411",
# NI Instrument Simulator v2.0
"Instrument Simulator", # single instrument
"Waveform Generator Simulator", # multi-instrument
]


class Function(Enum):
"""Enum that represents the measurement function."""

DC_VOLTS = 0
AC_VOLTS = 1


_FUNCTION_TO_VALUE = {
Function.DC_VOLTS: "VOLT:DC",
Function.AC_VOLTS: "VOLT:AC",
}


class Session:
"""An NI-VISA DMM session."""

def __init__(
self,
resource_name: str,
id_query: bool = True,
reset_device: bool = True,
simulate: bool = False,
) -> None:
"""Open NI-VISA DMM session."""
# Create a real or simulated VISA resource manager."""
visa_library = f"{_SIMULATION_YAML_PATH}@sim" if simulate else ""
resource_manager = pyvisa.ResourceManager(visa_library)

session = resource_manager.open_resource(
resource_name, read_termination="\n", write_termination="\n"
)

if not isinstance(session, pyvisa.resources.MessageBasedResource):
raise TypeError("The 'session' object must be an instance of MessageBasedResource.")
self._session = session

if id_query:
self._validate_id()

if reset_device:
self._reset()

def close(self) -> None:
"""Close the session."""
self._session.close()

def __enter__(self) -> Self:
"""Context management protocol. Returns self."""
return self

def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
traceback: Optional[TracebackType],
) -> None:
"""Context management protocol. Calls close()."""
self.close()

def configure_measurement_digits(
self, function: Function, range: float, resolution_digits: float
) -> None:
"""Configure the common properties of the measurement.
These properties include function, range, and resolution_digits.
"""
function_enum = _FUNCTION_TO_VALUE[function]
resolution_value = _RESOLUTION_DIGITS_TO_VALUE[str(resolution_digits)]

self._session.write("CONF:%s %.g,%.g" % (function_enum, range, resolution_value))
self._check_error()

def read(self) -> float:
"""Acquires a single measurement and returns the measured value."""
response = self._session.query("READ?")
self._check_error()
return float(response)

def _check_error(self) -> None:
"""Query the instrument's error queue."""
response = self._session.query("SYST:ERR?")
fields = response.split(",", maxsplit=1)
assert len(fields) >= 1
if int(fields[0]) != 0:
raise RuntimeError("Instrument returned error %s: %s" % (fields[0], fields[1]))

def _validate_id(self) -> None:
"""Check the selected instrument is proper and responding.."""
instrument_id = self._session.query("*IDN?")
if not any(id_check in instrument_id for id_check in _SUPPORTED_INSTRUMENT_IDS):
raise RuntimeError(
"The ID query failed. This may mean that you selected the wrong instrument, your instrument did not respond, "
f"or you are using a model that is not officially supported by this driver. Instrument ID: {instrument_id}"
)

def _reset(self) -> None:
"""Reset the instrument to a known state."""
self._session.write("*CLS")
self._session.write("*RST")
self._check_error()
32 changes: 32 additions & 0 deletions examples/output_voltage_measurement/_visa_dmm_sim.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
spec: "1.1"
devices:
VisaDmm:
eom:
GPIB INSTR:
q: "\n"
r: "\n"
dialogues:
- q: "*CLS"
- q: "*IDN?"
r: "National Instruments,Waveform Generator Simulator (simulated with pyvisa-sim),00000000,2.0.1"
- q: "*RST"
- q: "READ?"
r: "1.23456"
error:
error_queue:
- q: 'SYST:ERR?'
default: '0,No Error'
command_error: '-100,Command Error'
query_error: '-400,Query Error'
properties:
configuration:
default: "VOLT:DC 5.000000,0.001000"
getter:
q: "CONF?"
r: "{:s}"
setter:
q: "CONF:{:s}"

resources:
GPIB0::3::INSTR:
device: VisaDmm
67 changes: 0 additions & 67 deletions examples/output_voltage_measurement/_visa_helpers.py

This file was deleted.

Loading

0 comments on commit 8393c2d

Please sign in to comment.