|
|
|
|
@@ -1,3 +1,7 @@
|
|
|
|
|
"""
|
|
|
|
|
The main funciton generator module
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
### PLEASE DO NOT MIND THE FORMATTING, IT IS DONE AUTOMATICALLY BY 'BLACK' THE PYTHON FORMATTER
|
|
|
|
|
import logging
|
|
|
|
|
from typing import Literal
|
|
|
|
|
@@ -12,26 +16,25 @@ from .errors import UndefinedValueError, UndefinedCommunicationMethodError, Valu
|
|
|
|
|
class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
"""
|
|
|
|
|
This is an object representing the Rigol DG2052 function generator. This object uses the SCPI protocol for communicating with the Rigol DG2052 function generator.
|
|
|
|
|
|
|
|
|
|
Attributes
|
|
|
|
|
----------
|
|
|
|
|
port : str
|
|
|
|
|
The SCPI port describing the device, consists of a communication method and device port followed by the "::INSTR" keyword.
|
|
|
|
|
communication method: can be either USB or TCPIP (other communication methods are not supported for this device)
|
|
|
|
|
device port: either COMM4 or /dev/USB0 for USB in windows and posix systems respectively or the IP Address for TCPIP
|
|
|
|
|
|
|
|
|
|
format: "<communication method>::<device port>::INSTR"
|
|
|
|
|
|
|
|
|
|
example: "TCPI::192.168.1.11::INSTR" or "USB::COMM4::INSTR"
|
|
|
|
|
rm : ResourceManager
|
|
|
|
|
The resource manager object for pyvisa (for future use)
|
|
|
|
|
comm : CommMethod
|
|
|
|
|
The communication method used (either TCPIP or USB)
|
|
|
|
|
"""
|
|
|
|
|
# Attributes
|
|
|
|
|
# ----------
|
|
|
|
|
# port : str
|
|
|
|
|
# The SCPI port describing the device, consists of a communication method and device port followed by the "::INSTR" keyword.
|
|
|
|
|
# communication method: can be either USB or TCPIP (other communication methods are not supported for this device)
|
|
|
|
|
# device port: either COMM4 or /dev/USB0 for USB in windows and posix systems respectively or the IP Address for TCPIP
|
|
|
|
|
|
|
|
|
|
comm: CommMethod # The communication method used (either TCPIP or USB)
|
|
|
|
|
rm: ResourceManager # The resource manager object for pyvisa (for future use)
|
|
|
|
|
port: str # The str used for the port
|
|
|
|
|
# format: "<communication method>::<device port>::INSTR"
|
|
|
|
|
|
|
|
|
|
# example: "TCPI::192.168.1.11::INSTR" or "USB::COMM4::INSTR"
|
|
|
|
|
# rm : ResourceManager
|
|
|
|
|
# The resource manager object for pyvisa (for future use)
|
|
|
|
|
# comm : CommMethod
|
|
|
|
|
# The communication method used (either TCPIP or USB)
|
|
|
|
|
|
|
|
|
|
__comm: CommMethod # The communication method used (either TCPIP or USB)
|
|
|
|
|
__rm: ResourceManager # The resource manager object for pyvisa (for future use)
|
|
|
|
|
__port: str # The str used for the port
|
|
|
|
|
|
|
|
|
|
def __init__(self, port: str): # Class initialization method
|
|
|
|
|
"""
|
|
|
|
|
@@ -51,15 +54,15 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
"""
|
|
|
|
|
if "TCPIP" in port: # Check if port starts with TCPIP
|
|
|
|
|
logging.debug("(PROG) detected TCPIP port")
|
|
|
|
|
self.comm = CommMethod.LAN # Set comm to LAN
|
|
|
|
|
self.__comm = CommMethod.LAN # Set comm to LAN
|
|
|
|
|
elif "USB" in port: # Check if port starts with USB
|
|
|
|
|
logging.debug("(PROG) detected USB port")
|
|
|
|
|
self.comm = CommMethod.USB # Set comm to USB
|
|
|
|
|
self.__comm = CommMethod.USB # Set comm to USB
|
|
|
|
|
else: # Rause Undefined Communication Method Error
|
|
|
|
|
raise UndefinedCommunicationMethodError(port)
|
|
|
|
|
rm = ResourceManager() # Create a pyvisa.ResourceManager object
|
|
|
|
|
self.rm = rm # Save that object as rm
|
|
|
|
|
self.port = port # Save the port string as port
|
|
|
|
|
self.__rm = rm # Save that object as rm
|
|
|
|
|
self.__port = port # Save the port string as port
|
|
|
|
|
super().__init__(rm, port) # create tne instrument object
|
|
|
|
|
logging.debug("(PROG) created dg2052 instance")
|
|
|
|
|
self.open() # connect to the instrument object (for ease of use)
|
|
|
|
|
@@ -67,7 +70,7 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
|
|
|
|
|
def whoami(self) -> str:
|
|
|
|
|
"""
|
|
|
|
|
shows the identification of the connected instrument
|
|
|
|
|
Shows the identification of the connected instrument
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
@@ -75,7 +78,7 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
The identification of the connected instrument
|
|
|
|
|
"""
|
|
|
|
|
match (
|
|
|
|
|
self.comm
|
|
|
|
|
self.__comm
|
|
|
|
|
): # Return an Identification string depending on the communication method
|
|
|
|
|
# Here a match case is used to make it easy to extend the communication methods to other methods
|
|
|
|
|
case CommMethod.LAN: # if the communication method is LAN
|
|
|
|
|
@@ -98,7 +101,7 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
f"{manufacturer} {model}:\n\tSerial Nr.:"
|
|
|
|
|
+ f" {serial}\n\tSoftware Ver.:"
|
|
|
|
|
+ f" {software_ver}\n\tPort:"
|
|
|
|
|
+ f" {self.port}\n\tIPADDRESS: {ipaddr}\n\tMAC: {mac}"
|
|
|
|
|
+ f" {self.__port}\n\tIPADDRESS: {ipaddr}\n\tMAC: {mac}"
|
|
|
|
|
)
|
|
|
|
|
return out # return the formatted string
|
|
|
|
|
case CommMethod.USB: # if the communication method is USB
|
|
|
|
|
@@ -119,7 +122,7 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
f"{manufacturer} {model}:\n\tSerial Nr.:"
|
|
|
|
|
+ f" {serial}\n\tSoftware Ver.:"
|
|
|
|
|
+ f" {software_ver}\n\tPort:"
|
|
|
|
|
+ f" {self.port}\n\tINFORMATION: {info}"
|
|
|
|
|
+ f" {self.__port}\n\tINFORMATION: {info}"
|
|
|
|
|
)
|
|
|
|
|
return out # return the formatted string
|
|
|
|
|
case _: # default case raise Undefined Communication Method Error
|
|
|
|
|
@@ -145,6 +148,15 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
self.write(f":OUTP{channel} OFF")
|
|
|
|
|
|
|
|
|
|
def toggle_output(self, channel: Literal[1, 2]):
|
|
|
|
|
"""
|
|
|
|
|
Toggles the corresponding output channel
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
-------
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel of the device (either 1 or 2)
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
state = self.query(f":OUT{channel}?").strip()
|
|
|
|
|
logging.debug(f"(PROG) output {channel} state: {state}")
|
|
|
|
|
match (state):
|
|
|
|
|
@@ -176,26 +188,96 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
return low, high
|
|
|
|
|
|
|
|
|
|
def get_output_impedance(self, channel: Literal[1, 2]) -> float:
|
|
|
|
|
"""
|
|
|
|
|
Returns the output impedance.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel to get the impedance of
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
---
|
|
|
|
|
impedance: float
|
|
|
|
|
The impedance of the specified output channel
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
impedance = float(self.query(f":OUTP{channel}:IMP?"))
|
|
|
|
|
logging.debug(f"(PROG) output {channel} impedance: {impedance}")
|
|
|
|
|
return impedance
|
|
|
|
|
|
|
|
|
|
def get_output_load(self, channel: Literal[1, 2]) -> float:
|
|
|
|
|
"""
|
|
|
|
|
Returns the output load.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel to get the load of
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
---
|
|
|
|
|
load: float
|
|
|
|
|
The load of the specified output channel
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
load = float(self.query(f":OUTP{channel}:LOAD?"))
|
|
|
|
|
logging.debug(f"(PROG) output {channel} load: {load}")
|
|
|
|
|
return load
|
|
|
|
|
|
|
|
|
|
def get_output_signal(self, channel: Literal[1, 2]) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Returns the signal type and parameters.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
---
|
|
|
|
|
signal: str
|
|
|
|
|
The indentifier string of the signal.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
signal = self.query(f":SOUR{channel}:APPL?").strip()
|
|
|
|
|
logging.debug(f"(PROG) output {channel} signal: {signal}")
|
|
|
|
|
return signal
|
|
|
|
|
|
|
|
|
|
def get_output_state(self, channel: Literal[1, 2]) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Returns the output state of the signal
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
---
|
|
|
|
|
state: str
|
|
|
|
|
The state of the output (is either `"ON"` or `"OFF"`)
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
state = self.query(f":OUTP{channel}?").strip()
|
|
|
|
|
logging.debug(f"(PROG) output {channel} state: {state}")
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
def is_output_on(self, channel: Literal[1, 2]) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Returns a boolean representing the state of the output
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
---
|
|
|
|
|
state: bool
|
|
|
|
|
The state of the output (is either `True` or `False`)
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
channel_state = self.get_output_state(channel)
|
|
|
|
|
match channel_state:
|
|
|
|
|
case "ON":
|
|
|
|
|
@@ -206,6 +288,17 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
raise UndefinedValueError(channel_state, "ON or OFF")
|
|
|
|
|
|
|
|
|
|
def set_dc(self, channel: Literal[1, 2], offset: float):
|
|
|
|
|
"""
|
|
|
|
|
Sets the output channel to DC voltage mode
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
offset: float
|
|
|
|
|
The offset voltage
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
logging.debug(f"(PROG) set dc signal with offset: {offset}")
|
|
|
|
|
self.write(f":SOUR{channel}:APPL:DC 1,1,{offset}")
|
|
|
|
|
|
|
|
|
|
@@ -217,6 +310,23 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
offset: float = 0.0,
|
|
|
|
|
phase: int = 0,
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
Sets the output channel to A Sine Wave
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
freq: float, default:1e3
|
|
|
|
|
The frequency
|
|
|
|
|
amp: float, default:5.0
|
|
|
|
|
The Vpp amplitude
|
|
|
|
|
offset: float, default:0.0
|
|
|
|
|
The V offset
|
|
|
|
|
phase: int, default:0
|
|
|
|
|
The phase shift
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
if freq < SIN_RANGE[0] and freq > SIN_RANGE[1]:
|
|
|
|
|
raise ValueOutOfBoundsError(SIN_RANGE, freq)
|
|
|
|
|
if phase < 0 and phase > 360:
|
|
|
|
|
@@ -227,6 +337,17 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
self.write(f":SOUR{channel}:APPL:SIN {freq},{amp},{offset},{phase}")
|
|
|
|
|
|
|
|
|
|
def set_frequency(self, channel: Literal[1, 2], freq):
|
|
|
|
|
"""
|
|
|
|
|
Sets the frequency of the set signal
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
freq: float
|
|
|
|
|
The frequency
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
logging.debug(
|
|
|
|
|
f"(PROG) set wave frequency to {freq} Hz."
|
|
|
|
|
)
|
|
|
|
|
@@ -241,6 +362,23 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
offset: float = 0.0, # Sets the amplitude offset
|
|
|
|
|
phase: int = 0, # Sets the phase shift
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
Sets the output channel to A Square Wave
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
freq: float, default:1e3
|
|
|
|
|
The frequency
|
|
|
|
|
amp: float, default:5.0
|
|
|
|
|
The Vpp amplitude
|
|
|
|
|
offset: float, default:0.0
|
|
|
|
|
The V offset
|
|
|
|
|
phase: int, default:0
|
|
|
|
|
The phase shift
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
check_bounds(SQU_RANGE, freq)
|
|
|
|
|
check_bounds((0, 360), phase)
|
|
|
|
|
logging.debug(
|
|
|
|
|
@@ -256,6 +394,23 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
offset: float = 0, # Sets the amplitude offset
|
|
|
|
|
phase: int = 0, # Sets the phase shift
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
Sets the output channel to A Ramp (Triangular) Wave
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
The output channel
|
|
|
|
|
freq: float, default:1e3
|
|
|
|
|
The frequency
|
|
|
|
|
amp: float, default:5.0
|
|
|
|
|
The Vpp amplitude
|
|
|
|
|
offset: float, default:0.0
|
|
|
|
|
The V offset
|
|
|
|
|
phase: int, default:0
|
|
|
|
|
The phase shift
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
check_bounds(RAMP_RANGE, freq)
|
|
|
|
|
check_bounds((0, 360), phase)
|
|
|
|
|
logging.debug(
|
|
|
|
|
@@ -283,6 +438,47 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
trigger_slope: SweepTriggerSlope = SweepTriggerSlope.POSITIVE, # Sets the edge type of the trigger input signal (for external trigger only)
|
|
|
|
|
trigger_source: SweepTriggerSource = SweepTriggerSource.INTERNAL, # Sets the sweep trigger source
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
Sets the parameters of a signal sweep
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
Sets the output channel of the sweep function
|
|
|
|
|
amp: float, default:5
|
|
|
|
|
Sets the amplitude of the sweeped signal
|
|
|
|
|
offset: float, default:0
|
|
|
|
|
Sets the offset voltage of the sweeped signal
|
|
|
|
|
phase: int, default:0
|
|
|
|
|
Sets the phase shift of the sweeped signal
|
|
|
|
|
signal_type: SweepSignalType, default:SweepSignalType.SINE
|
|
|
|
|
Sets the type of signal being sweeped
|
|
|
|
|
htime_start: float, default:0
|
|
|
|
|
Sets the start hold time of the sweep function
|
|
|
|
|
htime_stop: float, default:0
|
|
|
|
|
Sets the stop hold time of the sweep function
|
|
|
|
|
freq_start: float, default:100
|
|
|
|
|
Sets the sweep starting frequency
|
|
|
|
|
freq_stop: float, default:1e3
|
|
|
|
|
Sets the sweep stopping frequency
|
|
|
|
|
marker: bool, default:False
|
|
|
|
|
Enables/Disables setting the marker frequency manually
|
|
|
|
|
freq_marker: float, default:550
|
|
|
|
|
Sets the marker frequency at whic the Sync signal changes from high to low
|
|
|
|
|
rtime: float, default:0
|
|
|
|
|
Sets the return time of the sweep function
|
|
|
|
|
time: float, default:1
|
|
|
|
|
Sets the sweep time
|
|
|
|
|
spacing: SweepSpacing, default:SweepSpacing.LIN
|
|
|
|
|
Sets the sweep type
|
|
|
|
|
step: int, default:2
|
|
|
|
|
Sets the number of steps of the sweep function
|
|
|
|
|
trigger_slope: SweepTriggerSlope, default:SweepTriggerSlope.POSITIVE
|
|
|
|
|
Sets the edge type of the trigger input signal (for external trigger only)
|
|
|
|
|
trigger_source: SweepTriggerSource, default:SweepTriggerSource.INTERNAL
|
|
|
|
|
Sets the sweep trigger source
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
time_bounds: tuple[float, float] = (0, 500)
|
|
|
|
|
command_header = f":SOUR{channel}:SWE"
|
|
|
|
|
check_bounds(time_bounds, htime_start)
|
|
|
|
|
@@ -333,4 +529,13 @@ class DG2052(pyvisa.resources.MessageBasedResource):
|
|
|
|
|
self.write(f"{command_header}:STAT ON")
|
|
|
|
|
|
|
|
|
|
def trigger_sweep(self, channel: Literal[1, 2]):
|
|
|
|
|
"""
|
|
|
|
|
Triggers a sweep manually (Only works if the sweep was setup with `trigger_source` as `SweepTriggerSource.MANUAL`)
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
---
|
|
|
|
|
channel: Literal[1, 2]
|
|
|
|
|
Sets the output channel of the sweep function
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
self.write(f":SOUR{channel}:SWE:TRIG:IMM")
|
|
|
|
|
|