Stanford Research Systems ‐‐ SG380 - ACBJayichLab/NV_ABJ GitHub Wiki
Compatible Equipment
This hardware implementation complies with the abstract definitions for a microwave source. It should be functionally compatible for models SG382, SG384, and SG386 however, only the SG384 has been tested so far.
[!CAUTION] The functionality of this class assumes a microwave switch is present before the microwaves are able to be delivered to the sample in question. Because of this when you turn on the signal to the SG380 series it will directly turn on the signal there is no priming that will occur. This means when utilizing this class for experimental logic it is assumed the SG380 series is connected to a microwave switch to control duration
Importing
from NV_ABJ.hardware_interfaces.microwave_sources.sg380.sg380 import *
Configuring The Source
There are two channels possible to use on the SG380 series either the BNC for lower frequency or N-Type ports for higher frequency signals.
The default for the channel is N-Type if you would like to change that or explicitly define it you can import SG380Channels from the same folder location.
sg380= SG380(gpib_address = "GPIB0::27::INSTR",
channel = SG380Channels.n_type)
The GPIB address above should be replaced with the address you are using for your signal generator it is a string. This module uses pyvisa so if you can interface using pyvisa that will sufficiently work for the class.
For the channel, you can define it as SG380Channels.n_type or SG380Channels.bnc to select the N-Type or BNC respectively.
Using the SG380 as a Microwave Source
Because this is a connected device you have the option to use a context manager which is recommend. This generally will appear as below.
with sg380:
sg380.set_frequency_hz(2.87e9)
sg380.set_power_dbm(-15)
sg380.turn_signal_on()
# Your experimental code here
This should be noted that you can achieve the same functionality using the below
[!IMPORTANT] If you are designing a experimental logic that will be applied to multiple systems it is recommend to use the function
generate_sine_wave_hz_dbmto allow for loading the function with non-relevant keywords that are necessary for other microwave sources.
with sg380:
sg380.generate_sine_wave_hz_dbm(frequency_hz = 2.87e9, power_dbm = -15)
sg380.turn_signal_on()
# Your experimental code here
This may appear a bit more clunky but if you're writing experimental logic this will be a better fit allowing us to define additional key words that are used by different instruments like an AWG may need the keyword "duration_s" to tell the function how long specifically to set the frequency for because a microwave switch is not needed for the implementation.
You may also interface the SG380 without a context manager. You may want to do this to circumvent the context manager turning off the signal on close. this is to make sure when we are running an experimental code the microwave source turns off reliably to avoid any issues of thermal heating or damaging the sample.
[!WARNING] Because of this the following method does not provide the error handling of the context manager we want to avoid this use for experimental logic applications
sg380.make_connection()
sg380.generate_sine_wave_hz_dbm(frequency_hz = 2.87e9, power_dbm = -15)
sg380.turn_signal_on()
# Your experimental code here
sg380.close_connection()
All Available Commands
Make Connection
Connects to the configured device. Clears any warnings, creates a pyvisa class and passes this to the resource manager. This also is where the device is checked to be a SG380 series and configures the output parameters such as power range, and frequency range for the selected channel.
sg380.make_connection()
Close Connection
This is used to close the connection to the SG380. It starts by turning off any outputting signal and then closes the resource manager and class for the configured SG380.
sg380.close_connection()
Frequency Range (property value)
The frequency range for this device is created when connected and depends on the device. It is hard codded based on the specifications of the SG380 series rather than retrieved from the device. This will return a tuple (minimum frequency, maximum frequency)
sg380.frequency_range_hz
Power Range (property value)
This returns the power range for the selected sg380 configuration and is a tuple (minimum power, maximum power)
sg380.power_range_dbm
Generate Sine Wave
This function generates the RF signal using the frequency and power. It will also turn on the signal generator making it reliant on the microwave switch for controlling duration. The expected behavior of this call is that the RF signal is primed for use when the sequence generator indicates it is ready.
[!IMPORTANT] This function should be the main method used for experimental logic as it is meant to be able to take in other key word arguments that are not relevant to the operation of the SG380
sg380.generate_sine_wave_hz_dbm(frequency_hz,power_dbm)
- frequency_hz(int) = input frequency in Hz
- power_dbm(float) = input power in dBm
Set Frequency Hz
This function is used to set the frequency of the SG380 it does the parsing to the correct command based on the output port that is specified in the device configuration
sg380.set_frequency_hz(frequency_hz)
- frequency_hz(int) = input frequency in Hz
Get Frequency Hz
This function will return a float of the queried frequency in Hz
frequency = sg380.get_frequency_hz()
Set the Power dBm
Sets the power in dBm of the sg380 it will use the correct command based on the port indicated in the device configuration
set_power_dbm(power_dbm)
- power_dbm(float) = input power in dBm
Get the Power in dBm
This will return a float based on the value of the power queried from the SG380. It will call the correct command based on your device configuration
power_dbm = sg380.get_power_dbm()
Turn on Signal
This is meant to turn on the RF output from the SG380 calling the correct command based on the device configuration
sg380.turn_on_signal()
Turn Off Signal
This will turn off the signal to the SG380 based on the device configuration
sg380.turn_off_signal()
Load Frequency List Hz
def load_frequency_list_hz(self,frequency_list):
"""This is meant to be a command to load a frequency list to a device if the device can't do this it can be implemented using the set frequency
and saving the list as a property to the class triggering you can just iterate through the list
"""
self.send_frequency_list(frequency_list)
self.trigger_list_item() # Goes to the first entrance on the list
def get_frequency_list_hz(self):
""" Returns a list of the currently loaded frequencies
"""
return self.get_frequency_list()
def iterate(self):
"""This will iterate through the loaded frequency list essentially setting the current frequency to the triggered values
"""
self.trigger_list_item()
#########################################################################################################################################################################
# Cascading commands
#########################################################################################################################################################################
def get_frequency_list(self):
size_of_list = int(self.get_list_size())
frequencies = []
for i in range(size_of_list):
freq = self.get_list_point(i)
frequencies.append(float(self.get_list_point(i).replace(",N,N,N,N,N,N,N,N,N,N,N,N,N,N\r\n","")))
return frequencies
def send_frequency_list(self,frequency_list):
# Sends the list of desired frequencies to the SRS through GPIB
self._srs.query(f"LSTC? {len(frequency_list)}")
self.clear_status()
for ind,f in enumerate(frequency_list):
command = f"LSTP {ind},{f},N,N,N,N,N,N,N,N,N,N,N,N,N,N"
self._srs.write(command)
self._srs.write("LSTE 1")
#########################################################################################################################################################################
# Default commands implemented
#########################################################################################################################################################################
def modulation_on(self):
self._srs.write("MODL 1")
def modulation_off(self):
self._srs.write("MODL 0")
def modulation_state(self):
return self._srs.query("MODL?")
def modulation_type(self,type:int):
"""
0 = AM
1 = FM
2 = PhiM (Phase)
3 = Sweep
4 = Pulse
5 = Blank
6 = IQ
"""
self._srs.write(f"TYPE {type}")
def get_modulation_type(self):
return self._srs.query("TYPE?")
def iq_modulation_noise(self):
self._srs.write("QFNC 4")
def iq_modulation_external(self):
self._srs.write("QFNC 5")
def get_iq_modulation(self):
return self._srs.query("QFNC?")
def n_type_on(self):
self._srs.write("ENBR 1")
def n_type_off(self):
self._srs.write("ENBR 0")
def n_type_state(self):
return self._srs.query("ENBR?")
def bnc_on(self):
self._srs.write("ENBL 1")
def bnc_off(self):
self._srs.write("ENBL 0")
def bnc_state(self):
return self._srs.query("ENBL?")
def change_frequency(self,frequency,unit= "MHz"):
if unit == "Hz":
self._srs.write('FREQ '+str(frequency))
else:
self._srs.write(f'FREQ {frequency} {unit}')
def get_current_frequency(self):
return self._srs.query("FREQ?")
def change_amplitude_n_type(self,amplitude):
self._srs.write('AMPR '+str(amplitude))
def get_n_type_amplitude(self):
return self._srs.query("AMPR?")
def change_amplitude_bnc(self,amplitude):
self._srs.write('AMPL '+str(amplitude))
def get_bnc_amplitude(self):
return self._srs.query("AMPL?")
def change_phase(self,phase):
self._srs.write('PHAS '+str(phase))
def get_phase(self):
return self._srs.query("PHAS?")
def get_list_point(self,number):
return self._srs.query(f"LSTP? {number}")
def get_list_size(self):
return self._srs.query("LSTS?")
def trigger_list_item(self):
# Triggers the next item on the list for the SRS using the DAQ
self._srs.write("*TRG")
def clear_status(self):
return self._srs.write("*CLS")
def check_connection(self):
response = self._srs.query("*IDN?")
if "Stanford Research Systems,SG384" in response:
return response
else:
raise Exception("Failed to confirm srs connection id may be incorrect")