2024-10-30 11:50:26 +00:00
# -*- coding: utf-8 -*-
"""
Created on 29.10 .2024 , 09 : 00 hrs
LC Controller measurement script
@author : Serdar , adjusted by Lukas and Ryan
"""
############################################
# Packages from Ryan
import re
import math
import threading
import pyvisa
import time
# from pyvisa import ResourceManager, constants
# NOTE: KLCCommandLib64.py must be in the same folder as this script!
try :
from KLCCommandLib64 import *
except OSError as ex :
print ( " Warning: " , ex )
2024-10-31 09:16:31 +00:00
V_MAX = 25 # corresponds to the max RMS voltage of 25 V of KLC101 device
2024-10-30 11:50:26 +00:00
############################################
import AMC
import csv
import time
import clr
import sys
2024-10-31 09:16:31 +00:00
import os , glob , string
2024-10-30 11:50:26 +00:00
import spe2py as spe
import spe_loader as sl
import pandas as pd
import time
from System . IO import *
from System import String
import numpy as np
import matplotlib . pyplot as plt
import datetime
from typing import Union
# NOTE: this is possibly not needed, remove later
#First choose your controller
IP_AMC300 = " 192.168.1.1 "
IP_AMC100 = " 192.168.71.100 "
# IP = "192.168.1.1"
IP = IP_AMC100
# Import System.IO for saving and opening files
from System . IO import *
from System . Threading import AutoResetEvent
# Import C compatible List and String
from System import String
from System . Collections . Generic import List
# Add needed dll references
sys . path . append ( os . environ [ ' LIGHTFIELD_ROOT ' ] )
sys . path . append ( os . environ [ ' LIGHTFIELD_ROOT ' ] + " \\ AddInViews " )
sys . path . append ( r ' C: \ Program Files \ Princeton Instruments \ LightField \ AddInViews ' ) #I added them by hand -serdar
sys . path . append ( r ' C: \ Program Files \ Princeton Instruments \ LightField ' ) #this one also
clr . AddReference ( ' PrincetonInstruments.LightFieldViewV5 ' )
clr . AddReference ( ' PrincetonInstruments.LightField.AutomationV5 ' )
clr . AddReference ( ' PrincetonInstruments.LightFieldAddInSupportServices ' )
os . environ [ ' LIGHTFIELD_ROOT ' ] = r ' C: \ Program Files \ Princeton Instruments \ LightField '
# PI imports
from PrincetonInstruments . LightField . Automation import Automation
from PrincetonInstruments . LightField . AddIns import ExperimentSettings
from PrincetonInstruments . LightField . AddIns import CameraSettings
#from PrincetonInstruments.LightField.AddIns import DeviceType
from PrincetonInstruments . LightField . AddIns import SpectrometerSettings
from PrincetonInstruments . LightField . AddIns import RegionOfInterest
######################################################################################################### code begins from here #############################################
def set_custom_ROI ( ) :
# Get device full dimensions
dimensions = experiment . FullSensorRegion ( )
regions = [ ]
# Add two ROI to regions
regions . append (
RegionOfInterest (
int ( dimensions . X ) , int ( dimensions . Y ) ,
int ( dimensions . Width ) , int ( dimensions . Height / / 4 ) , # Use // for integer division
int ( dimensions . XBinning ) , int ( dimensions . Height / / 4 ) ) )
# Set both ROI
experiment . SetCustomRegions ( regions )
def experiment_completed ( sender , event_args ) : #callback function which is hooked to event completed, this is the listener
print ( " ... Acquisition Complete! " )
acquireCompleted . Set ( ) #set the event. This puts the autoresetevent false.(look at .NET library for furher info)
def InitializerFilenameParams ( ) :
experiment . SetValue ( ExperimentSettings . FileNameGenerationAttachIncrement , False )
experiment . SetValue ( ExperimentSettings . FileNameGenerationIncrementNumber , 1.0 )
experiment . SetValue ( ExperimentSettings . FileNameGenerationIncrementMinimumDigits , 2.0 )
experiment . SetValue ( ExperimentSettings . FileNameGenerationAttachDate , False )
experiment . SetValue ( ExperimentSettings . FileNameGenerationAttachTime , False )
def AcquireAndLock ( name ) :
print ( " Acquiring... " , end = " " )
# name += 'Exp{0:06.2f}ms.CWL{1:07.2f}nm'.format(\
# experiment.GetValue(CameraSettings.ShutterTimingExposureTime)\
# ,experiment.GetValue(SpectrometerSettings.GratingCenterWavelength))
experiment . SetValue ( ExperimentSettings . FileNameGenerationBaseFileName , name ) #this creates .spe file with the name
experiment . Acquire ( ) # this is an ashynrchronus func.
acquireCompleted . WaitOne ( )
def calculate_distance ( x1 , y1 , x2 , y2 ) :
return np . sqrt ( ( x2 - x1 ) * * 2 + ( y2 - y1 ) * * 2 )
def generate_scan_positions ( center , range_val , resolution ) :
positive_range = np . arange ( center , center + range_val + resolution , resolution )
return positive_range
def save_as_csv ( filename , position_x , position_y ) :
file_existance = os . path . isfile ( filename )
with open ( filename , ' a ' , newline = ' ' ) as csvfile :
writer = csv . writer ( csvfile )
if not file_existance :
writer . writerow ( [ ' x_coordinates ' , ' y_coordinates ' ] )
writer . writerow ( [ position_x , position_y ] )
# def move_axis(axis, target):
# """
# This function moves an axis to the specified target and stop moving after it is in the really closed
# vicinity (+- 25nm) of the target (listener hooked to it).
# """
# amc.move.setControlTargetPosition(axis, target)
# amc.control.setControlMove(axis, True)
# while not (target - 25) < amc.move.getPosition(axis) < (target + 25):
# time.sleep(0.1)
# time.sleep(0.15)
# while not (target - 25) < amc.move.getPosition(axis) < (target + 25):
# time.sleep(0.1)
# amc.control.setControlMove(axis, False)
# def move_xy(target_x, target_y): # moving in x and y direction closed to desired position
# amc.move.setControlTargetPosition(0, target_x)
# amc.control.setControlMove(0, True)
# amc.move.setControlTargetPosition(1, target_y)
# amc.control.setControlMove(1, True)
# while not (target_x - 25) < amc.move.getPosition(0) < (target_x + 25) and (target_y - 25) < amc.move.getPosition(1) < (target_y + 25):
# time.sleep(0.1)
# time.sleep(0.15)
# while not (target_x - 25) < amc.move.getPosition(0) < (target_x + 25) and (target_y - 25) < amc.move.getPosition(1) < (target_y + 25):
# time.sleep(0.1)
# amc.control.setControlOutput(0, False)
# amc.control.setControlOutput(1, False)
# intensity_data = [] # To store data from each scan
# data_list = []
# def move_scan_xy(range_x, range_y, resolution, Settings, baseFileName):
# """
# This function moves the positioners to scan the sample with desired ranges and resolution in 2 dimensions.
# At the end it saves a csv file
# Parameters
# ----------
# range_x : integer in nm. max value is 5um
# Scan range in x direction.
# range_y : integer in nm. max value is 5um
# Scan range in y direction.
# resolution : integer in nm.
# Room temprature max res is 50nm. In cyrostat (4K) it is 10nm (check the Attocube manual)
# baseFileName: string. At the end the saved file will be: baseFileName_scan_data.csv and it will be saved to the current directory
# Returns
# -------
# None.
# """
# start_time = time.time()
# axis_x = 0 #first axis
# axis_y = 1 #second axis
# center_x = amc.move.getPosition(axis_x)
# center_y = amc.move.getPosition(axis_y)
# # #check if the intput range is reasonable
# # if amc.move.getPosition(axis_x) + range_x >= 5000 or amc.move.getPosition(axis_x)- range_x <= 0 or amc.move.getPosition(axis_y) + range_y >=5000 or amc.move.getPosition(axis_y) - range_y <= 5000 :
# # print("scan range is out of range!")
# # return
# # +- range from current positions for x and y directions
# array_x = generate_scan_positions(center_x, range_x, resolution)
# array_y = generate_scan_positions(center_y, range_y, resolution)
# total_points = len(array_x)*len(array_y)
# len_y = len(array_y)
# intensity_data = [] # To store data from each scan
# data_list = []
# cwd = os.getcwd() # save original directory
# #This gives a directory, in which the script will save the spectrum of each spot as spe
# #However, it will open the spectrum, convert it to txt, add it to the intensity_data and delete the spe file
# temp_folder_path = "C:/Users/localadmin/Desktop/Users/Lukas/2024_02_08_Map_test"
# #scanning loop
# for i, x_positions in enumerate(array_x):
# move_axis(axis_x, x_positions)
# y = False
# for j, y_positions in enumerate(array_y):
# move_axis(axis_y, y_positions)
# #each time when the positioner comes to the beggining of a new line
# #this if will make the positioner wait a bit longer to really go to the target.
# if y == False:
# move_axis(axis_y, y_positions)
# y = True
# #we acquire with the LF
# acquire_name_spe = f'{baseFileName}_X{x_positions}_Y{y_positions}'
# AcquireAndLock(acquire_name_spe) #this creates a .spe file with the scan name.
# #read the .spe file and get the data as loaded_files
# cwd = os.getcwd() # save original directory
# os.chdir(temp_folder_path) #change directory
# loaded_files = sl.load_from_files([acquire_name_spe + '.spe']) # get the .spe file as a variable
# os.chdir(cwd) # go back to original directory
# # Delete the created .spe file from acquiring after getting necessary info
# spe_file_path = os.path.join(temp_folder_path, acquire_name_spe + '.spe')
# os.remove(spe_file_path)
# distance = calculate_distance(x_positions, y_positions,amc.move.getPosition(axis_x), amc.move.getPosition(axis_y))
# points_left = total_points - (i * len_y + (j+1)) + 1
# print('Points left in the scan: ', points_left)
# #append the intensity data as it is (so after every #of_wl_points, the spectrum of the next point begins)
# intensity_data.append(loaded_files.data[0][0][0])
# data_list.append({
# 'position_x': x_positions,
# 'position_y': y_positions,
# 'actual_x': amc.move.getPosition(axis_x),
# 'actual_y': amc.move.getPosition(axis_y),
# 'distance': distance,
# })
# #moves back to starting position
# move_axis(axis_x, center_x)
# move_axis(axis_y, center_y)
# #prints total time the mapping lasted
# end_time = time.time()
# elapsed_time = (end_time - start_time) / 60
# print('Scan time: ', elapsed_time, 'minutes')
# # df = pd.DataFrame(data_list)
# #save intensity & WL data as .txt
# os.chdir('C:/Users/localadmin/Desktop/Users/Lukas')
# # creates new folder for MAP data
# new_folder_name = "Test_Map_" + f"{datetime.datetime.now().strftime('%Y_%m_%d_%H.%M')}"
# os.mkdir(new_folder_name)
# # Here the things will be saved in a new folder under user Lukas !
# # IMPORTANT last / has to be there, otherwise data cannot be saved and will be lost!!!!!!!!!!!!!!!!
# os.chdir('C:/Users/localadmin/Desktop/Users/Lukas/'+ new_folder_name)
# intensity_data = np.array(intensity_data)
# np.savetxt(Settings + str(center_x) + '_' + str(center_y) + experiment_name +'.txt', intensity_data)
# wl = np.array(loaded_files.wavelength)
# np.savetxt("Wavelength.txt", wl)
################################################################# RYAN'S FUNCTIONS HERE ##########################################################################################
def polar_to_cartesian ( radius , start_angle , end_angle , step_size , clockwise = True ) :
# TODO: DOCS
""" Creates a list of discrete cartesian coordinates (x,y), given the radius, start- and end angles, the angle step size, and the direction of rotation.
Function then returns a list of two lists : list of angles and list of cartesian coordinates ( x , y coordinates in a tuple ) .
Args :
radius ( _type_ ) : _description_
start_angle ( _type_ ) : _description_
end_angle ( _type_ ) : _description_
step_size ( _type_ ) : _description_
clockwise ( bool , optional ) : _description_ . Defaults to True .
Returns :
_type_ : _description_
""" """ """
# Initialize lists to hold angles and (x, y) pairs
angles = [ ]
coordinates = [ ]
# Normalize angles to the range [0, 360)
start_angle = start_angle % 360
end_angle = end_angle % 360
if clockwise :
# Clockwise rotation
current_angle = start_angle
while True :
# Append the current angle to the angles list
angles . append ( current_angle % 360 )
# Convert the current angle to radians
current_angle_rad = math . radians ( current_angle % 360 )
# Convert polar to Cartesian coordinates
x = radius * math . cos ( current_angle_rad )
y = radius * math . sin ( current_angle_rad )
# Append the (x, y) pair to the list
coordinates . append ( ( x , y ) )
# Check if we've reached the end_angle (handling wrap-around) (current_angle - step_size) % 360 == end_angle or
if current_angle % 360 == end_angle :
break
# Decrement the current angle by the step size
current_angle - = step_size
if current_angle < 0 :
current_angle + = 360
else :
# Counterclockwise rotation
current_angle = start_angle
while True :
# Append the current angle to the angles list
angles . append ( current_angle % 360 )
# Convert the current angle to radians
current_angle_rad = math . radians ( current_angle % 360 )
# Convert polar to Cartesian coordinates
x = radius * math . cos ( current_angle_rad )
y = radius * math . sin ( current_angle_rad )
# Append the (x, y) pair to the list
coordinates . append ( ( x , y ) )
# Check if we've reached the end_angle (handling wrap-around) (current_angle + step_size) % 360 == end_angle or
if current_angle % 360 == end_angle :
break
# Increment the current angle by the step size
current_angle + = step_size
if current_angle > = 360 :
current_angle - = 360
return [ angles , coordinates ]
################################################################# DASHA'S CODE HERE ##############################################################################################
# TODO: modify b field scan script for Dasha, to be used for the KLC controller
2024-10-31 09:16:31 +00:00
def LCR_scan_func ( handle : int , init_voltage : float , final_voltage : float ,
res : float , base_file_name = ' ' ,
2024-10-30 11:50:26 +00:00
reversescan_bool = False , zerowhenfin_bool = False , loopscan_bool = False ) - > None :
def pyramid_list ( lst ) - > Union [ list , np . ndarray ] :
""" reverses the list and removes the first element of reversed list. Then, this is appended to
the end of the original list and returned as the ' pyramid ' list .
Args :
lst ( list or np . ndarray ) :
Raises :
TypeError : if the input object isn ' t a list or np.ndarray
Returns :
Union [ list , np . ndarray ] : the pyramid list
""" ' ' ' ' ' '
if isinstance ( lst , list ) :
return lst + lst [ - 2 : : - 1 ]
elif isinstance ( lst , np . ndarray ) :
return np . append ( lst , lst [ - 2 : : - 1 ] )
else :
raise TypeError ( ' Please input a list! ' )
# defines the folder, in which the data from the spectrometer is temporarily stored in
2024-10-31 09:16:31 +00:00
temp_folder_path = " C:/Users/localadmin/Desktop/Users/Dasha/LCR_temp_dump_folder "
2024-10-30 11:50:26 +00:00
if base_file_name == ' ' :
base_file_name = datetime . datetime . now ( ) . strftime ( ' % Y_ % m_ %d _ % H. % M ' )
start_time = time . time ( ) # start of the scan function
2024-10-31 09:16:31 +00:00
# if '2101014' in instr_info and (magnet_coil=='y-axis'): # single power supply
2024-10-30 11:50:26 +00:00
# if (min_bval< -BY_MAX) or (max_bval > BY_MAX):
# raise ValueError('Input limits exceed that of the magnet By! Please input smaller limits.')
2024-10-31 09:16:31 +00:00
# elif '2301034' in instr_info: # dual power supply
# if magnet_coil=='z-axis': # check if its the coils for Bz
# if (min_bval < -BZ_MAX) or (max_bval > BZ_MAX):
# raise ValueError('Input limits exceed that of the magnet (Bz)! Please input smaller limits.')
# write_no_echo(instr, 'CHAN 1')
# elif magnet_coil=='x-axis': # checks limits of Bx
# if (min_bval< -BX_MAX) or (max_bval > BX_MAX):
# raise ValueError('Input limits exceed that of the magnet Bx! Please input smaller limits.')
# write_no_echo(instr, 'CHAN 2')
# else:
# raise ConnectionError('Device is not connected!')
2024-10-30 11:50:26 +00:00
write_no_echo ( instr , f ' LLIM { min_bval * 10 } ;ULIM { max_bval * 10 } ' ) # sets the given limits, must convert to kG for the device to read
bval_lst = np . arange ( min_bval , max_bval + res , res ) # creates list of B values to measure at, with given resolution, in T
init_lim , subsequent_lim = ' LLIM ' , ' ULIM '
init_sweep , subsequent_sweep = ' DOWN ' , ' UP '
# if reverse scan, then flip the values in the b list, and swap the initial limit and sweep conditions
if reversescan_bool :
bval_lst = bval_lst [ : : - 1 ]
init_lim , subsequent_lim = subsequent_lim , init_lim
init_sweep , subsequent_sweep = subsequent_sweep , init_sweep
# creates the pyramid list of B vals if one were to perform a hysteresis measurement
if loopscan_bool :
bval_lst = pyramid_list ( bval_lst )
total_points = len ( bval_lst )
middle_index_bval_lst = total_points / / 2
intensity_data = [ ] # To store data from each scan
cwd = os . getcwd ( ) # save original directory
# NOTE: helper function for the scanning loop
def helper_scan_func ( idx , bval , instr = instr , init_lim = init_lim , init_sweep = init_sweep ,
subsequent_lim = subsequent_lim , subsequent_sweep = subsequent_sweep , sleep = 5 ) :
if idx == 0 : # for first iteration, sweep to one of the limits
write_no_echo ( instr , f ' { init_lim } { bval * 10 } ' ) # convert back to kG
write_no_echo ( instr , f ' SWEEP { init_sweep } ' )
else :
write_no_echo ( instr , f ' { subsequent_lim } { bval * 10 } ' ) # convert back to kG
write_no_echo ( instr , f ' SWEEP { subsequent_sweep } ' )
actual_bval = sep_num_from_units ( query_no_echo ( instr , ' IMAG? ' ) ) [ 0 ] * 0.1 # convert kG to T
print ( f ' Actual magnet strength: { actual_bval } T, ' , f ' Target magnet strength: { bval } T ' )
while abs ( actual_bval - bval ) > 0.0001 :
time . sleep ( 5 ) # little break
actual_bval = sep_num_from_units ( query_no_echo ( instr , ' IMAG? ' ) ) [ 0 ] * 0.1
# update the actual bval
print ( f ' Actual magnet strength: { actual_bval } T, ' , f ' Target magnet strength: { bval } T ' )
#scanning loop
for i , bval in enumerate ( bval_lst ) :
if not loopscan_bool :
helper_scan_func ( i , bval )
else :
if i < = middle_index_bval_lst :
helper_scan_func ( i , bval )
else :
helper_scan_func ( i , bval , instr = instr , init_lim = subsequent_lim , init_sweep = subsequent_sweep ,
subsequent_lim = init_lim , subsequent_sweep = init_sweep , sleep = 5 )
time . sleep ( 5 )
# we acquire with the LF
acquire_name_spe = f ' { base_file_name } _ { bval } T '
AcquireAndLock ( acquire_name_spe ) #this creates a .spe file with the scan name.
# read the .spe file and get the data as loaded_files
cwd = os . getcwd ( ) # save original directory
os . chdir ( temp_folder_path ) #change directory
loaded_files = sl . load_from_files ( [ acquire_name_spe + ' .spe ' ] ) # get the .spe file as a variable
os . chdir ( cwd ) # go back to original directory
# Delete the created .spe file from acquiring after getting necessary info
spe_file_path = os . path . join ( temp_folder_path , acquire_name_spe + ' .spe ' )
os . remove ( spe_file_path )
2024-10-31 09:16:31 +00:00
points_left = total_points - i - 1
2024-10-30 11:50:26 +00:00
print ( ' Points left in the scan: ' , points_left )
#append the intensity data as it is (so after every #of_wl_points, the spectrum of the next point begins)
intensity_data . append ( loaded_files . data [ 0 ] [ 0 ] [ 0 ] )
#prints total time the mapping lasted
end_time = time . time ( )
elapsed_time = ( end_time - start_time ) / 60
print ( ' Scan time: ' , elapsed_time , ' minutes ' )
write_no_echo ( instr , f ' LLIM { instr_bsettings [ 1 ] [ 0 ] * 10 } ;ULIM { instr_bsettings [ 2 ] [ 0 ] * 10 } ' ) # reset the initial limits of the device after the scan
if zerowhenfin_bool :
write_no_echo ( instr , ' SWEEP ZERO ' ) # if switched on, discharges the magnet after performing the measurement loop above
#save intensity & WL data as .txt
os . chdir ( ' C:/Users/localadmin/Desktop/Users/Lukas ' )
# creates new folder for MAP data
new_folder_name = " Test_Map_ " + f " { datetime . datetime . now ( ) . strftime ( ' % Y_ % m_ %d _ % H. % M ' ) } "
os . mkdir ( new_folder_name )
# Here the things will be saved in a new folder under user Lukas !
# IMPORTANT last / has to be there, otherwise data cannot be saved and will be lost!!!!!!!!!!!!!!!!
os . chdir ( ' C:/Users/localadmin/Desktop/Users/Lukas/ ' + new_folder_name )
intensity_data = np . array ( intensity_data )
2024-10-31 09:16:31 +00:00
np . savetxt ( base_file_name + ' .txt ' , intensity_data )
2024-10-30 11:50:26 +00:00
wl = np . array ( loaded_files . wavelength )
np . savetxt ( " Wavelength.txt " , wl )
################################################################# END OF FUNCTION DEFS ###########################################################################################
# NOTE: RYAN INTRODUCED SOME FUNCTIONS HERE TO PERFORM THE SCAN
try :
# initialise KLC connection
2024-10-31 09:16:31 +00:00
# Find devices
2024-10-30 11:50:26 +00:00
devs = klcListDevices ( )
print ( " Found devices: " , devs , " \n " )
if ( len ( devs ) < = 0 ) :
print ( ' There is no device connected ' )
sys . exit ( )
klc = devs [ 0 ]
serialnumber = klc [ 0 ]
2024-10-31 09:16:31 +00:00
# Connect device
2024-10-30 11:50:26 +00:00
KLC_handle = klcOpen ( serialnumber , 115200 , 3 )
if ( KLC_handle < 0 ) :
print ( " open " , serialnumber , " failed " )
sys . exit ( )
if ( klcIsOpen ( serialnumber ) == 0 ) :
print ( " klcIsOpen failed " )
klcClose ( KLC_handle )
sys . exit ( )
print ( " Connected to serial number " , serialnumber )
2024-10-31 09:16:31 +00:00
# TODO: remove this commented code block later
2024-10-30 11:50:26 +00:00
# Initialise PYVISA ResourceManager
2024-10-31 09:16:31 +00:00
# rm = pyvisa.ResourceManager()
2024-10-30 11:50:26 +00:00
# print(rm.list_resources())
# 'ASRL8::INSTR' for dual power supply, 'ASRL9::INSTR' for single power supply (online PC)
# 'ASRL10::INSTR' for dual power supply, 'ASRL12::INSTR' for single power supply (offline PC)
auto = Automation ( True , List [ String ] ( ) )
experiment = auto . LightFieldApplication . Experiment
acquireCompleted = AutoResetEvent ( False )
2024-10-31 09:16:31 +00:00
experiment . Load ( " Alison_08.07.24 " ) # NOTE: this should be the
2024-10-30 11:50:26 +00:00
experiment . ExperimentCompleted + = experiment_completed # we are hooking a listener.
# experiment.SetValue(SpectrometerSettings.GratingSelected, '[750nm,1200][0][0]')
# InitializerFilenameParams()
2024-10-31 09:16:31 +00:00
# ENTER START AND END VOLTAGES, AS WELL AS VOLTAGE STEP SIZE HERE
start_voltage = 0
end_voltage = 0.5
voltage_stepsize = 0.25
2024-10-30 11:50:26 +00:00
#Here you can specify the filename of the map e.g. put experiment type, exposure time, used filters, etc....
experiment_settings = ' PL_SP_700_LP_700_HeNe_52muW_exp_2s_Start_ '
#The program adds the range of the scan as well as the resolution and the date and time of the measurement
2024-10-31 09:16:31 +00:00
experiment_name = f " { start_voltage } V_to_ { end_voltage } V_ { voltage_stepsize } V_ { datetime . datetime . now ( ) . strftime ( ' % Y_ % m_ %d _ % H % M ' ) } "
2024-10-30 11:50:26 +00:00
# TODO: insert LCR rotation scan function here
2024-10-31 09:16:31 +00:00
# use this reference code for the LCR scan later on
# sweep_b_val(powerbox_dualsupply, set_llim_bval, set_ulim_bval, set_res_bval, 'z-axis',
# experiment_settings, base_file_name=experiment_name, zerowhenfin_bool=True, reversescan_bool=False)
2024-10-30 11:50:26 +00:00
except Exception ( ) as e :
print ( e )
finally :
#close connection to device
klcClose ( KLC_handle )
print ( " Connection closed " )