🌊
LabRAD入門④:実際の測定コードの例
ゲート制御可能な2次元電子系の低温測定では基本の測定である、磁場とゲート電圧を変調させて電気抵抗を測定するという測定コードをコメント付きで載せておきます。(下記コードを実際に実験を行っていたときに使っていたコードの一部なのでPython2で書かれており、かつ一部コメントが英語になっています。)ほぼ完全版はこちら、またラボで使われていたコード例はこちら。
使用機器は
import labrad
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import scipy.io as sio
from matplotlib.ticker import ScalarFormatter
import datetime
import time
import math
import os
import inspect
import sys
sns.set('talk', 'whitegrid', 'dark', font_scale=1.2,
rc={"lines.linewidth": 2, 'grid.linestyle': '--'})
cxn = labrad.connect()
cxn_2 = labrad.connect()
cxn_3 = labrad.connect()
#時定数のパラメーター
tcdel = 3.0
ramp_step = 1000
ramp_delay = 2500
# Initialization
sim = cxn.sim900
sim.select_device()
#ロックインアンプを3台使うので明示的に各GPIB番号を指定
LA1 = cxn.sr860
LA1.select_device('pc_name GPIB Bus - GPIB0::1::INSTR')
LA2 = cxn_2.sr860
LA2.select_device('pc_name GPIB Bus - GPIB0::2::INSTR')
LA3 = cxn_3.sr860
LA3.select_device('pc_name GPIB Bus - GPIB0::3::INSTR')
time_constant_1 = LA1.time_constant()
sensitivity_1 = LA1.sensitivity()
#COM番号を明示的に指定
MGz = cxn.ami_430
MGz.select_device('pc_name_serial_server - COM1')
####################################################
#関数の引数を返す関数:パラメーターに何を入れたか記録するのに便利
# credit: https://tottoto.net/python3-get-args-of-current-function/
def get_meas_parameters(offset=None):
parent_frame = inspect.currentframe().f_back
info = inspect.getargvalues(parent_frame)
return {key: info.locals[key] for key in info.args[offset:]}
# ロックインの振幅と周波数を設定
def set_lockin_parameters(amplitude, frequency):
LA1.sine_out_amplitude(amplitude)
LA1.frequency(frequency)
time.sleep(1)
print '\r',"parameters set done",
# データ記録ファイルの生成
def create_file(file_path, scan_name, scan_var, meas_var):
DV = cxn.data_vault
try:
DV.mkdir(file_path)
DV.cd(file_path)
except Exception:
DV.cd(file_path)
file_name = file_path + '_' + scan_name
dv_file = DV.new(file_name, scan_var, meas_var)
print '\r',"new file created, file numer: ", int(dv_file[1][0:5])
return int(dv_file[1][0:5])
# txtファイルに測定パラメーターなどの情報を書き込み
def write_meas_parameters(DV, file_path, file_number, date, scan_name, meas_parameters, amplitude, sensitivity):
if not os.path.isfile(meas_details_path+file_path+'.txt'):
with open(meas_details_path+file_path+'.txt', "w") as f:
f.write("-------------------------------------"+ "\n")
f.write("file_number: "+ str(file_number) + "\n" + "date: " + str(date) +"\n" + "measurement:" + str(scan_name) + "\n")
for k, v in sorted(meas_parameters.items()):
print(k, v)
f.write(str(k) + ": "+ str(v) + "\n")
else:
with open(meas_details_path+file_path+'.txt', "a") as f:
f.write("-------------------------------------"+ "\n")
f.write("file_number: "+ str(file_number) + "\n" + "date: " + str(date) +"\n" + "measurement:" + str(scan_name) + "\n")
for k, v in sorted(meas_parameters.items()):
print(k, v)
f.write(str(k) + ": "+ str(v) + "\n")
t_mc0, t_p0 = read_T()
f.write("MXC temperature: "+ str(t_mc0) + "\n" + "probe temperature: "+ str(t_p0) + "\n")
time_constant_1 = LA1.time_constant()
sensitivity_1 = LA1.sensitivity()
time_constant_2 = LA2.time_constant()
sensitivity_2 = LA2.sensitivity()
time_constant_3 = LA3.time_constant()
sensitivity_3 = LA3.sensitivity()
f.write("time_constant_1: "+ str(time_constant_1) + "\n" + "time_constant_2: "+ str(time_constant_2) + "\n" + "time_constant_3: "+ str(time_constant_3) + "\n")
f.write("sensitivity_1: "+ str(sensitivity_1) + "\n" + "sensitivity_2: "+ str(sensitivity_2) + "\n" + "sensitivity_3: "+ str(sensitivity_3) + "\n")
# 測定にかかったトータル時間を書き込み
def write_meas_parameters_end(date1, date2, file_path):
with open(meas_details_path+file_path+'.txt', "a") as f:
f.write("end date: " + str(date2) + "\n"+ "total time: " + str(date2-date1)+ "\n")
# hdf5ファイル内のコントロール変数と測定変数を出力
def get_variables():
variables = [DV.variables()[0][i][0] for i in range(len(DV.variables()[0]))] + [DV.variables()[1][i][0] for i in range(len(DV.variables()[1]))]
return variables
# グラフを描画
def plot_fig(file_name, file_num, data, cl, xsize, ysize, xaxis, yaxis, xscale, yscale, xname, yname, logy, var, unit):
df = pd.DataFrame(data.T, columns=cl)
fig = plt.figure()
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
df[yaxis[1]] = abs(df[yaxis[1]])
df.plot(x=xaxis, y=yaxis[0], logy=logy[0], ax=ax1, figsize=(xsize, ysize))
df.plot(x=xaxis, y=yaxis[1], logy=logy[1], ax=ax2, figsize=(xsize, ysize))
df.plot(x=xaxis, y=yaxis[2], logy=logy[2], ax=ax3, figsize=(xsize, ysize))
ax1.set_xlabel(xname)
ax1.set_ylabel(yname[0])
ax2.set_xlabel(xname)
ax2.set_ylabel(yname[1])
ax3.set_xlabel(xname)
ax3.set_ylabel(yname[2])
ax1.set_xlim(xscale[0], xscale[1])
ax2.set_xlim(xscale[0], xscale[1])
ax3.set_xlim(xscale[0], xscale[1])
ax1.set_ylim(yscale[0], yscale[1])
ax2.set_ylim(yscale[2], yscale[3])
ax3.set_ylim(yscale[4], yscale[5])
ax1.legend(bbox_to_anchor=(0.85, 1.11), loc='upper left', borderaxespad=0, fontsize=18)
ax2.legend(bbox_to_anchor=(0.85, 1.11), loc='upper left', borderaxespad=0, fontsize=18)
ax3.legend(bbox_to_anchor=(0.85, 1.11), loc='upper left', borderaxespad=0, fontsize=18)
ax1.legend().set_visible(False)
ax2.legend().set_visible(False)
ax3.legend().set_visible(False)
plt.rcParams["font.family"] = "sans-serif"
plt.rcParams["mathtext.fontset"] = "stixsans"
fig.patch.set_facecolor('white')
fig.tight_layout()
# sim900の電圧値をある範囲で制御し、その時のロックインアンプの電圧値を出力
def sim_sweep(out_ch, vstart, vend, points, delay):
vs = [[0] * points]
vs = np.linspace(vstart, vend, num = points)
d_tmp = None
p1, p2, p3 = 0, 0, 0
for jj in range(points):
sim.dc_set_voltage(out_ch,float("{0:.4f}".format(vs[jj])))
time.sleep(delay*0.9)
try:
#line_data = [DAC.read_voltage(k) for k in in_dac_ch]
p1, p2, p3 = LA1.x(), LA2.x(), LA3.x()
line_data = [p1, p2, p3]
except:
line_data = [p1, p2, p3]
if d_tmp:
d_tmp = np.vstack([d_tmp, line_data])
else:
d_tmp = line_data
return d_tmp.T
# sim900で電圧値を設定
def set_Vg_nodac(voltage_source, dc_channel_0, start_v, end_v):
sim_sweep(dc_channel_0, start_v, end_v, 100, 0.02)
time.sleep(1)
print '\r',"Voltage reached: ",end_v," V",
# sim900の電圧を変化させた場合のロックインアンプの電圧値を出力から電気抵抗などを計算し, numpy arrayとして出力
def scan_Vg(meas_voltage_gain, dc_channel_0, start_v, end_v, number_of_vg_points, wait_time):
vg = np.linspace(start_v, end_v, number_of_vg_points)
print '\r','Scanning Vg: Start_V:', start_v, ' V; End_V:', end_v, ' V',
res = sim_sweep(dc_channel_0, start_v, end_v, number_of_vg_points, wait_time/4/1e6)
res_1, res_2, res_3 = res
# Calculate resistance
res_5 = np.float64(1.0)*res_2/res_1/meas_voltage_gain
res_6 = np.float64(1.0)*res_3/res_1/meas_voltage_gain
# Calculate conductance
res_7 = np.float64(1.0)/res_5
res_8 = np.float64(1.0)/res_6
return np.array([res_1, res_2, res_3, res_5, res_6, res_7, res_8])
# AMI420/430という装置で磁場を目標値に設定
def set_Bz(MGz, target_bz):
MGz.conf_ramp_rate_field(1, 0.0606, 9.0)
MGz.conf_field_targ(float(target_bz))
MGz.ramp()
print '\r',"Ramping magnetic field to ",target_bz," T",
flag = True
while flag:
try:
actual_field = float(MGz.get_field_mag())
flag = False
except:
flag = True
while abs(float(target_bz)- float(MGz.get_field_mag())) >1.0e-4:
continue
time.sleep(1)
print '\r',"Magnetic field reached: ",target_bz," T",
return float(MGz.get_field_mag())
# Lakeshoreで温度の読み取り
def read_T():
reconnected = False
while not reconnected:
try:
time.sleep(1.0)
print '\r', "Connecting to temperature server ..."
#cxn4 = labrad.connect('evaporator-PC', 7682, password='pass')
cxn4 = labrad.connect()
tc = cxn4.lakeshore_372
tc.select_device()
Tmc, T_p = tc.mc(), tc.probe()
print '\r', 'MXC: ', Tmc, 'probe: ', T_p
time.sleep(1.0)
print '\r', 'Reconnected successfully',
return Tmc, T_p
except Exception as e:
print '\r', str(e),
print '\r', 'Could not reconnect to temperature server',
time.sleep(2.0)
# Lakeshoreで温度の設定
def set_T(setpoint):
setpoint_updated = False
while not setpoint_updated:
try:
expression = "SETP 0, %03.2E\n"%setpoint
#print '\r', expression
tc.write(expression) # set the power for the current zone
Tmc, T_p = tc.mc(), tc.probe()
print '\r', 'MXC: ', Tmc, 'probe: ', T_p,
if setpoint < 1.0:
temperature_error = min(setpoint*0.03, 0.01)
elif setpoint > 6.5 and setpoint < 10.0:
temperature_error = 0.3
elif setpoint > 10.0: temperature_error = 1.0
else: temperature_error = 0.1
while abs(Tmc - setpoint) > temperature_error:
time.sleep(2.0)
Tmc, T_p = tc.mc(), tc.probe()
print '\r', 'current MXC: ', Tmc, 'current probe: ', T_p,
print '\r', 'Target temperature reached.',
return Tmc, T_p
setpoint_updated = True
except Exception as e:
print '\r', str(e),
print '\r', 'Failed to update setpoint',
reconnected = False
while not reconnected:
try:
print '\r', "Connecting to temperature server ...",
#cxn4 = labrad.connect('evaporator-PC', 7682, password='pass')
cxn4 = labrad.connect()
tc = cxn4.lakeshore_372
tc.select_device()
Tmc, T_p = tc.mc(), tc.probe()
print '\r', 'MXC: ', Tmc, 'probe: ', T_p,
print '\r', 'Reconnected successfully',
reconnected = True
except Exception as e:
print '\r', str(e),
print '\r', 'Could not reconnect to temperature server',
time.sleep(2.0)
# 電気抵抗(ロックインアンプSR860で測定)をゲート電圧(sim900で制御)と磁場(AMI420/430で制御)に対して測定、データを保存、データをプロット
def scan_R_vs_Vg_Bz(misc, file_path, amplitude, frequency, gate_gain, meas_voltage_gain, voltage_source, voltage_channel,bz_range, vg_range, number_of_bz_lines, number_of_vg_points, wait_time):
#Get date, parameters and scan name
cxn0 = labrad.connect()
DV = cxn0.data_vault
date1 = datetime.datetime.now()
meas_parameters = get_meas_parameters()
scan_name = sys._getframe().f_code.co_name
#Initial settings of lockins
set_lockin_parameters(amplitude, frequency)
#Create data file and save measurement parameters
scan_var = ('Vg_ind', 'Vg', 'Bz_ind', 'Bz', 'Bz_ac', 'Tmc', 'Tp')
meas_var = ('Ix', 'V1', 'V2', 'R1', 'R2', 'G1', 'G2')
file_number = create_file(DV, file_path, scan_name, scan_var, meas_var)
write_meas_parameters(DV, file_path, file_number, date1, scan_name, meas_parameters, amplitude, frequency)
#Create data points/grids
b_lines = np.linspace(bz_range[0], bz_range[1], number_of_bz_lines)
t_mc0, t_p0 = read_T()
##### Measurements start #####
# go to initial gate volatge
set_Vg_nodac(voltage_channel, 0.0, vg_range[0])
for ind, val in enumerate(b_lines, 1):
actual_B = set_Bz(MGz, val)
print '\r',"Field Line:", ind, "out of ", number_of_bz_lines
vg_ind = np.linspace(1, number_of_vg_points, number_of_vg_points)
vg = gate_gain* np.linspace(vg_range[0], vg_range[1], number_of_vg_points)
b_ind = np.linspace(ind, ind, number_of_vg_points)
b_val = val * np.ones(number_of_vg_points)
b_ac = actual_B * np.ones(number_of_vg_points)
t_mc = t_mc0 * np.ones(number_of_vg_points)
t_p = t_p0 * np.ones(number_of_vg_points)
data1 = np.array([vg_ind, vg, b_ind, b_val, b_ac, t_mc, t_p])
# Scan Vg and acquire data
data2 = scan_Vg(meas_voltage_gain, voltage_channel, vg_range[0], vg_range[1], number_of_vg_points, wait_time/4)
data = np.vstack((data1, data2))
DV.add(data.T)
# if the scan line is 1, plot the line data.
if number_of_bz_lines == 1:
plot_fig(file_name = scan_name, file_num = file_number,
data = data, cl = list(scan_var) + list(meas_var),
xsize = 12, ysize = 16, xaxis = "Vg",
yaxis = ['Ix', 'R1', 'R2'], xscale = [None, None],
yscale = [None, None, 1, 50000, -1000, 1000],
xname = "Vg", yname = ['Ix', 'R1', 'R2'],
logy = [False, True, False], var = 0, unit = "T")
# go to next gate voltage
if ind < number_of_bz_lines:
set_Vg_nodac(voltage_source, voltage_channel, vg_range[1], vg_range[0])
# go to 0 V
set_Vg_nodac(voltage_source, voltage_channel, vg_range[1], 0.0)
print '\r',"measurement number: ", file_number, scan_name, " done"
##### Measurements done #####
date2 = datetime.datetime.now()
write_meas_parameters_end(date1, date2, file_path)
def main():
scan_R_vs_Vg_Bz(misc = 'example', file_path = 'sample1',
amplitude = 1.0, frequency = 17.777,
gate_gain = 1.0, meas_voltage_gain = 1.0,
voltage_channel = 1, bz_range = [0.0, 12.0],
vg_range = [-5.0, 5.0], number_of_bz_lines = 100,
number_of_vg_points = 1000,
wait_time = 1e6*tcdel*time_constant_1)
if __name__ == '__main__':
main()
<b>参考</b>
Discussion