Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Experiment Photoreflectance #4

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions Devices/Dev_AMT/Dummy_T_UNSW.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
__author__ = 'Andrew M. Telford & Diego Alonso-Álvarez'

# Libraries
import datetime

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg

from tkinter import messagebox, ttk
import tkinter as tk
from tkinter import filedialog

import numpy as np
import time

from serial import Serial

# Class definition
class Dummy_T_UNSW(object):
def __init__(self, port='COM4', name='Lakeshore 336', info=None):
self.info = {}
self.info['Name'] = name
if info is not None:
self.info.update(info)

self.device = "Dummy"

self.setPoint = 300
self.temperature = 300

print(self.getID())

def close(self):
self.device.close()

def getID(self):
return ("Dummy T Controller")

def getTemp(self):
self.temperature = self.setPoint
return self.temperature

def getSP(self):
self.setPoint = self.temperature
return self.setPoint

def setSP(self, value):
self.setPoint = value

def setHeater(self, value):
pass


class New(Dummy_T):
""" Standarised name for the Lakeshore336 class"""
pass


# Testing
if __name__ == '__main__':
root = tk.Tk()
root.withdraw()
test = T_controller(master=root)
root.mainloop()
55 changes: 55 additions & 0 deletions Devices/Dummy_HF2LI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Libraries
import time
import random
from tkinter import messagebox


# Class definition
class Dummy_HF2LI:

def __init__(self, port=None, name='Dummy HF2LI', info=None):
self.info = {}
self.info['Name'] = name
if info is not None:
self.info.update(info)

self.integration_time = 300
self.min_wavelength = 0.

def readTimeconstant(self):
""" Reads the integration time selected in the lockin
:return:
"""
return self.integration_time

def update_integration_time(self, new_time):
""" Updates the integration time in the lockin based on the selection in the program
:param new_time: the new integration time selected in the program
:return:
"""
self.integration_time = new_time

print('Integration time: {} ms'.format(self.integration_time))
return self.integration_time

def open(self):
pass

def measure(self):
return random.random(), random.random(), random.random(), random.random(), random.random(), random.random()

def close(self):
pass

def interface(self, master):
messagebox.showinfo(message='No specific configuration available for {0}'.format(self.info['Name']),
detail='Press OK to continue.', title='Device configuration')

class New(Dummy_HF2LI):
""" Standarised name for the Dummy_monochromator class"""
pass

# Testing
if __name__ == "__main__":
test = New('COM4')
print(test.measure())
135 changes: 128 additions & 7 deletions Devices/Dummy_ZA.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ def __init__(self, address='GPIB::20', name='Dummy ZA', info=None):
if info is not None:
self.info.update(info)

# Opening the device is essential. Here is an example for a VISA-based instrument
# rm = visa.ResourceManager()
# self.device = rm.open_resource("{}".format(address))
##self.device = None

##self.i_range = ['auto', '1e-9 A', '10e-9 A', '100e-9 A', '1e-6 A', '10e-6 A', '100e-6 A', '1e-3 A', '10e-3 A',
## '100e-3 A']
##self.v_range = ['auto', '1.1 V', '11 V']
##self.log_points = ['5', '10', '25', '50']
##self.int_time = ['0.416', '4', '16.67', '20']

def query(self, msg):
""" Send a message to the instrument and then waits for an answer. depending on the nature of the device and
Expand Down Expand Up @@ -56,39 +66,150 @@ def close(self):
pass


def set_za_function(self, fixed):
def set_za_function(self, function, fixed):
""" Sets the functionality of the source, what to bias and how to do it.

:param fixed: variable indicating whethe rbias or frequency are fixed
:param function: 'dc' or 'sweep', dc or sweep operating function
:param source: 'v' or 'i', voltage or current source
:return: None
"""

self.fixed = fixed
#self.function = function


def update_compliance(self, compliance, measRange):
""" Updates the compliance and the measurement range.

:param compliance: current or voltage compliance, oposite to the selected source
:param measRange: the meas range as the index of self.i_range or self.v_range
:return: None
"""

self.compliance = compliance
self.measRange = measRange


def update_integration_time(self, new_time):
""" Sets the integration time.

:param new_time: new integration time as the index from the self.int_time list
:return: None
"""

self.itime = new_time


def update_waiting_time(self, new_time):
""" Sets the delay time between setting a bias and starting a measurement

:param new_time: New delay time in ms.
:return: None
"""
self.delay = new_time


def setup_measurement(self, plot_format, options):
""" Sets up the scan.
""" Prepares and triggers the IV measurement.

:param function: 'dc' or 'sweep', dc or sweep operating function
:param source: 'v' or 'i' for voltage or current biasing, respectively
:param compliance: meas compliance
:param measRange: the meas range as the index of self.i_range or self.v_range
:param delay: the delay between applying a bias and taking the meas
:param intTime: integration time as the index from the self.int_time list
:return: The measured data
"""

##self.set_source_function(function, fixed)
##self.update_compliance(compliance, measRange)
##self.update_integration_time(intTime)
##self.update_waiting_time(delay)

## Setup fixed variable, its value, and the sweep parameters.


def measure(self, options):
""" Starts the scan.
""" Prepares and triggers the IV measurement.

:param source: 'v' or 'i' for voltage or current biasing, respectively
:param start: start bias
:param stop: stop bias
:param points: points to measure per decade in current bias mode
:param step: step size in voltage bias mode
:param compliance: meas compliance
:param measRange: the meas range as the index of self.i_range or self.v_range
:param delay: the delay between applying a bias and taking the meas
:param intTime: integration time as the index from the self.int_time list
:return: The estimated measuring time
"""

# First we setup the experiment

# We program the sweep.
# We typically will use the AUTO fixed range for the bias, as it might cover may orders of magnitude


# We estimate the runing time of the sweep, set the timeout time accordingly and return the control to the IV module.
# This will wait in a "safe way" during the measurement, avoiding freezing the program
#self.totalPoints = nop
#minimumWait = 1 ## in ms
#measTime = self.totalPoints * minimumWait
##if self.measRange == 0:
## measTime = measTime * 10
# self.device.timeout = None
#print("Waiting for Dummy.\nEstimated measurement time = {} s".format(measTime / 1000))


# Finally, we trigger the sweep. Depending on the SMU, you might need to turn it on first


#return measTime


##def set_bias(self, biasValue=0.0):
""" Set a bias to the source. If the source is not turned on or the function is not set to 'dc',
the bias will not be applied

:param biasValue: the chosen bias
:return: None
"""

# First we check that the experiment has been setup for DC bias/meas
##if self.function != 'dc':
## print('DC measurement not setup correctly. Call self.setup_experiment before setting the bias')
## return

# Set the bias in the SMU

# And triger it, if need it


def return_data(self):
""" Generate random data for testing.
""" We get the data fromt he SMU. Depending on the order provided by the SMU we need to invert the output to
have voltage-current, regardless of who is the bias or the meas. We convert the data to an array and re-shape
it in two columns.

:return: the generated data, a tuple with two vectors: voltage and current
:return: the measured data, a tuple with two vectors: voltage and current
"""

# If we are in sweep function, we have to really wait until the meas is finished. In some SMU this is not needed
# as they will not response until they are finished. In others, they don't like to be bothered while measuring.
# Then, we have to turn off the source if not done automatically. In the dc function, the source is turn off externally

totalPoints = 100
# Get the data.
# Here we just simulate some random data. two points for DC or a large number for a sweep
data = np.random.rand(3*totalPoints)
data = np.array(data, dtype=np.float32).reshape((-1, 3))

return data[:, 0], data[:, 1], data[:, 2]

# Depending of what we are biasing, we might need to invert the order of the output
# We assume in the example that the source produces bias-meas and we want voltage-current, so we invert it
##if self.source == 0:
return data[:, 0], data[:, 1], data[:, 2]
##else:
## return data[:, 1], data[:, 0]

def operate_off(self):
""" Turn off the output of the SMU
Expand Down
69 changes: 69 additions & 0 deletions Devices/HF2LI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Libraries
import numpy as np
from tkinter import messagebox
import zhinst.ziPython, zhinst.utils

debug = False
developing = False

# Class definition
class HF2LI:
def __init__(self, port=None, name='Zurich Inst HF2LI', info=None):
self.info = {}
self.info['Name'] = name
if info is not None:
self.info.update(info)
self.integration_time = 100
self.min_wavelength = 0.
self.daq = zhinst.ziPython.ziDAQServer('localhost', 8005)

def open(self, demod=[0,1,2]):
""" Subscribes to two demodulators to exctract data.
:param demod: list of 2 demodulator numbers (in Python numbering)
:return: none
"""
self.daq.subscribe('/dev1370/demods/'+str(demod[0])+'/sample')
self.daq.subscribe('/dev1370/demods/'+str(demod[1])+'/sample')
self.daq.subscribe('/dev1370/demods/'+str(demod[2])+'/sample')

def measure(self):
self.daq.sync()
timeout = self.integration_time + 200
raw_data = self.daq.poll(self.integration_time/1000, timeout)
Xc = np.mean(raw_data['dev1370']['demods']['0']['sample']['x'])
Yc = np.mean(raw_data['dev1370']['demods']['0']['sample']['y'])
Xsum = np.mean(raw_data['dev1370']['demods']['1']['sample']['x'])
Ysum = np.mean(raw_data['dev1370']['demods']['1']['sample']['y'])
Xdif = np.mean(raw_data['dev1370']['demods']['2']['sample']['x'])
Ydif = np.mean(raw_data['dev1370']['demods']['2']['sample']['y'])
return Xc, Yc, Xsum, Ysum, Xdif, Ydif

def update_integration_time(self, new_time):
""" Updates the integration time in the lockin based on the selection in the program
:param new_time: the new integration time selected in the program
:return:
"""
self.integration_time = new_time

print('Integration time: {} ms'.format(self.integration_time))
return self.integration_time


def close(self, demod=[0,1,2]):
self.daq.unsubscribe('/dev1370/demods/'+str(demod[0])+'/sample')
self.daq.unsubscribe('/dev1370/demods/'+str(demod[1])+'/sample')
self.daq.unsubscribe('/dev1370/demods/'+str(demod[2])+'/sample')

def interface(self, master):
messagebox.showinfo(message='No specific configuration available for {0}'.format(self.info['Name']),
detail='Press OK to continue.', title='Device configuration')


class New(HF2LI):
""" Standarised name for the HF2LI class"""
pass

# Testing
if __name__=="__main__":
test = New()
print(test.update_integration_time(0.800))
Loading