diff --git a/hp4194/SCPI_command_summary.csv b/hp4194/SCPI_command_summary.csv new file mode 100644 index 0000000000000000000000000000000000000000..f19a9b7db14668408b67f54bbf2d759daec053c1 --- /dev/null +++ b/hp4194/SCPI_command_summary.csv @@ -0,0 +1,204 @@ +Command;Mnemonic;Comment;Section +FNC1;meas_imp;Impedance Measurement;Function +FNC2;meas_gain_phase;Gain Phase Measurement;Function +FNC3;meas_imp_Z;Impedance Measurement with Z-Probe;Function +IMP1;imp_Z_theta;/Z/-theta;Measurement function for impedance +IMP2;imp_R_X;R-X;Measurement function for impedance +IMP3;imp_Ls_Rs;Ls-Rs;Measurement function for impedance +IMP4;imp_Ls_Q;Ls-Q;Measurement function for impedance +IMP5;imp_Cs_Rs;Cs-Rs;Measurement function for impedance +IMP6;imp_Cs_Q;Cs-Q;Measurement function for impedance +IMP7;imp_Cs_D;Cs_D;Measurement function for impedance +IMP8;imp_Y_theta;/Y/-theta;Measurement function for impedance +IMP9;imp_G_B;G_B;Measurement function for impedance +IMP10;imp_Lp_G;Lp-G;Measurement function for impedance +IMP11;imp_Lp_Q;Lp-Q;Measurement function for impedance +IMP12;imp_Cp_G;Cp_G;Measurement function for impedance +IMP13;imp_Cp_Q;Cp-Q;Measurement function for impedance +IMP14;imp_Cp_D;Cp-D;Measurement function for impedance +IMP15;imp_Z_Ls;/Z/-Ls;Measurement function for impedance +IMP16;imp_Z_Cs;/Z/-Cs;Measurement function for impedance +IMP17;imp_Z_Lp;/Z/-Lp;Measurement function for impedance +IMP18;imp_Z_Cp;/Z/-Cp;Measurement function for impedance +IMP19;imp_Lp_Rp;Lp-Rp;Measurement function for impedance +IMP20;imp_Cp_Rp;Cp-Rp;Measurement function for impedance +GPP1;gp_Tch_Rch_dB_theta;Tch/Rch(dB)-theta;Measurement function for gain-phase +GPP2;gp_Tch_Rch_theta;Tch/Rch-theta;Measurement function for gain-phase +GPP3;gp_Tch_Rch_dB_tau;Tch/Rch(dB)-tau;Measurement function for gain-phase +GPP4;gp_Rch_Tch_V;Rch-Tch(V);Measurement function for gain-phase +GPP5;gp_Rch_Tch_dBm;Rch-Tch(dBm);Measurement function for gain-phase +GPP6;gp_Rch_Tch_dBv;Rch-Tch(dBV);Measurement function for gain-phase +IVM0;imp_monitor_off;off;Monitor function for impedance +IVM1;imp_monitor_V;V(AC);Monitor function for impedance +IVM2;imp_monitor_I;I(AC);Monitor function for impedance +GNM0;gp_monitor_off;off;Monitor function for gain-phase +GNM1;gp_monitor_Rch_V;Rch(V);Monitor function for gain-phase +GNM2;gp_monitor_Rch_dBm;Rch(dBm);Monitor function for gain-phase +GNM3;gp_monitor_Rch_dBV;Rch(dBV);Monitor function for gain-phase +GNM4;gp_monitor_Tch_V;Tch(V);Monitor function for gain-phase +GNM5;gp_monitor_Tch_dBm;Tch(dBm);Monitor function for gain-phase +GNM6;gp_monitor_Tch_dBV;Tch(dBV);Monitor function for gain-phase +SWP1;sweep_freq;Frequency;Sweep parameter +SWP2;sweep_bias;DC Bias (Impedance measurement only);Sweep parameter +SWP3;sweep_osc_V;Osc level (V);Sweep parameter +SWP4;sweep_osc_dBm;Osc level (dBm) (Linear sweep only);Sweep parameter +SWP5;sweep_osc_dBV;Osc level (dBV) (Linear sweep only);Sweep parameter +SWT1;sweep_lin;Linear ;Sweep type +SWT2;sweep_log;Logarithmic;Sweep type +SWD1;sweep_up;Up;Sweep direction +SWD2;sweep_down;Down;Sweep direction +PPM0;prog_point_meas_off;off;Programmed point measurement +PPM1;prog_point_meas_on;on;Programmed point measurement +MKEXP;exec_sweep_markers;Execute sweep between markers;o-marker to *-marker sweep +CMP1;interpolation_mode;Interpolation mode;Compensation for impedance measurement +CMP2;all_points_mode;All points mode;Compensation for impedance measurement +ZOPEN;start_open_cal;Start open calibration;Compensation for impedance measurement +ZSHRT;start_short_cal;Start short calibration;Compensation for impedance measurement +OPN0;open_cal_off;Open calibration off;Compensation for impedance measurement +OPN1;open_cal_on;Open calibration on;Compensation for impedance measurement +SHT0;short_cal_off;Short calibration off;Compensation for impedance measurement +SHT1;short_cal_on;Short calibration on;Compensation for impedance measurement +CALY;start_0S_cal;Start 0S calibration;Compensation for impedance measurement +CALZ;start_0Ohm_cal;Start 0Ohm calibration;Compensation for impedance measurement +CALSTD;start_std_cal;start 50Ohm (standard) calibration;Compensation for impedance measurement +CAL0;std_cal_off;standard calibration off;Compensation for impedance measurement +CAL1;std_caL_on;standard calibration on;Compensation for impedance measurement +PHS1;phase_scale_normal;Phase scale to normal mode;Compensation (impedance and gain- phase) +PHS2;phase_scale_expand;Phase scale to expansion mode;Compensation (impedance and gain-phase) +OFSTR;store_offset_ref;Store offset reference;Compensation for gain-phase measurement +AOF0;data_A_offset_off;Data A offset off;Compensation for gain-phase measurement +AOF1;data_A_offset_on;Data A offset on;Compensation for gain-phase measurement +BOF0;data_B_offset_off;Data B offset of;Compensation for gain-phase measurement +BOF1;data_B_offset_on;Data B offset on;Compensation for gain-phase measurement +DSP1;disp_X_AB;X-A&B;Display Mode +DSP2;disp_A_B;A-B;Display Mode +DSP3;disp_table;Table;Display Mode +AUTOA;autoscale_A;autoscale A;Display Fuction for X-A&B mode +AUTOB;autoscale_B;autoscale B;Display Fuction for X-A&B mode +DPA0;disp_A_off;display data A off;Display Fuction for X-A&B mode +DPA1;disp_A_on;display data A on;Display Fuction for X-A&B mode +DPB0;disp_B_off;display data B off;Display Fuction for X-A&B mode +DPB1;disp_B_on;display data B on;Display Fuction for X-A&B mode +AUTO;autoscale;Autoscale A/B both;Display Fuction for A-B mode +DPAB0;disp_AB_off;Display data A/B both off;Display Fuction for A-B mode +DPAB1;disp_AB_on;Display data A/B both on;Display Fuction for A-B mode +ASC1;scale_A_lin;Data A scale to linear;Display function for X-A&B and A-B modes +ASC2;scale_A_log;Data A scale to log;Display function for X-A&B and A-B modes +BSC1;scale_B_lin;Data B scale to linear;Display function for X-A&B and A-B modes +BSC2;scale_B_log;Data B scale to log;Display function for X-A&B and A-B modes +AMAX;set_A_max;Maximum value for data A scale;Display function for X-A&B and A-B modes +AMIN;set_A_min;Minimum value for data A scale;Display function for X-A&B and A-B modes +BMAX;set_B_max;Maximum value for data B scale;Display function for X-A&B and A-B modes +BMIN;set_B_min;Minimum value for data B scale;Display function for X-A&B and A-B modes +ADIV;set_A_div;Scale Division for data A ;Display function for X-A&B and A-B modes +BDIV;set_B_div;Scale Division for data B ;Display function for X-A&B and A-B modes +GRT0;graticule_off;Graticule off;Display function for X-A&B and A-B modes +GRT1;graticule_on;Graticule on;Display function for X-A&B and A-B modes +STRG0;storage_off;Storage off;Display function for X-A&B and A-B modes +STRG1;storage_on;Storage on;Display function for X-A&B and A-B modes +UNIT0;unit_disp_off;Unit Display On;Display Function +UNIT1;unit_disp_on;Unit Display Off;Display Function +LINE;set_top_line_num;Top Line number(1 to 401);Display Function for table mode +STSET;page_self_test;Setup self test page;Self Test +STN;set_self_test_num;set self test number;Self Test +STSET;start_self_test;start self test;Self Test +STSTP;stop_self_test;stop self test;Self Test +STEND;exit_self_test_page;end self test page;Self Test +EQSDP;page_circuit;Display Equivalent circuit page;Equivalent circuit +EQC1;circuit_A;Select A;Equivalent circuit +EQC2;circuit_B;Select B;Equivalent circuit +EQC3;circuit_C;Select C;Equivalent circuit +EQC4;circuit_D;Select D;Equivalent circuit +EQC5;circuit_E;Select E;Equivalent circuit +EQCAL;circuit_cal;Calculate equivalent circuit parameters;Equivalent circuit +EQVR;set_circuit_R;Equivalent circuit paramter R (Ohm);Equivalent circuit +EQVL;set_circuit_L;Equivalent circuit paramter L (H);Equivalent circuit +EQVCA;set_circuit_Ca;Equivalent circuit paramter Ca(F);Equivalent circuit +EQVCB;set_circuit_Cb;Equivalent circuit paramter Cb(F);Equivalent circuit +FCHRS;sim_freq_chars;Simulate frequency characteristics;Equivalent circuit +PTSET;page_points_tab;set programmed points table page;Set Programmed Points Table +PTN;points_tab_num;Programmed points table number(1-16);Set Programmed Points Table +PTCLR;clear_points_tab;Clear Programmed points table;Set Programmed Points Table +PTSWP1;sweep_par_to_freq;Sweep parameter to frequency;Set Programmed Points Table +PTSWP2;sweep_par_to_bias;Sweep parameter to DC bias;Set Programmed Points Table +PTSWP3;sweep_par_to_osc_V;Sweep parameter to Osc level (V);Set Programmed Points Table +PTSWP4;sweep_par_to_osc_dBm;Sweep parameter to Osc level (dBm);Set Programmed Points Table +PTSWP5;sweep_par_to_osc_dBV;Sweep parameter to Osc level (dBV);Set Programmed Points Table +LMF1;lim_data_A;Limit for data A;Set Programmed Points Table +LMF2;lim_data_B;Limit for data B;Set Programmed Points Table +POINT;set_prog_point;Programmed point(point,minimum ,maximum);Set Programmed Points Table +PTSORT;sort_points_tab;Sort programmed points table ;Set Programmed Points Table +PTEND;exit_points_tab_page;End Programmed points table set-up;Set Programmed Points Table +SWM1;sweep_repeat;sweep mode to repeat;Sweep +SWM2;sweep_single;sweep mode to single;Sweep +SWTRG;start_sweep;sweep start trigger;Sweep +ITM1;short;Integration Time to short 500us;Integration Time +ITM2;medium;Integration Time to medium 5ms;Integration Time +ITM3;long;Integration Time to long 100ms;Integration Time +NOA;aver_num;Averaging Number(power of 2 from 1 to 256);Averaging number +START;set_start;None;Parameter +STOP;set_stop;None;Parameter +STEP;set_step;None;Parameter +CENTER;set_center;None;Parameter +SPAN;set_span;None;Parameter +NOP;set_nop;Number of measurement points;Parameter +FREQ;set_freq;Spot Frequency (HZ);Parameter +BIAS;set_bias;Spot bias voltage(V);Parameter +OSC;set_osc;Spot osc level (V/dBm/dBV);Parameter +SAVE;save;save measurement state(0-4);Parameter +GET;get;get measurement state;Parameter +DTIME;set_delay_time;0 to 1 hour in ms;Parameter +DFREQ;set_delay_apperture;0.50 to 100%;Parameter +DCOFF;bias_off;DC bias off;Parameter +PWS1;power_splitter_single;None;Measurement Unit +PWS2;power_splitte_dual;None;Measurement Unit +ATR1;ref_attenuation_0dB;Reference Channel;Measurement Unit +ATR2;ref_attenuation_20dB;Reference Channel;Measurement Unit +ZIR1;ref_input_1MOhm;Reference Channel;Measurement Unit +ZIR2;ref_input_50Ohm;Reference Channel;Measurement Unit +ATT1;test_attenuation_0db;Test Channel;Measurement Unit +ATT2;test_attenuation_20db;Test Channel;Measurement Unit +ZIT1;test_input_1MOhm;Test Channel;Measurement Unit +ZIT2;test_input_50Ohm;Test Channel;Measurement Unit +RST;reset;Reset the Instrument;Reset +A;reg_A;Register for display data A;Register +B;reg_B;Register for display data B;Register +C;reg_super_A;Register for display superimpose data A;Register +D;reg_super_B;Register for display superimpose data B;Register +E;reg_gen_1;General purpose register;Register +F;reg_gen_2;General purpose register;Register +G;reg_gen_3;General purpose register;Register +H;reg_gen_4;General purpose register;Register +I;reg_gen_5;General purpose register;Register +J;reg_gen_6;General purpose register;Register +RA;reg_gen_7;General purpose register;Register +RB;reg_gen_8;General purpose register;Register +RC;reg_gen_9;General purpose register;Register +RD;reg_gen_10;General purpose register;Register +RE;reg_gen_11;General purpose register;Register +RF;reg_gen_12;General purpose register;Register +RG;reg_gen_13;General purpose register;Register +RH;reg_gen_14;General purpose register;Register +RI;reg_gen_15;General purpose register;Register +RI;reg_gen_16;General purpose register;Register +RK;reg_gen_17;General purpose register;Register +RL;reg_gen_18;General purpose register;Register +OFSTA;reg_offset_A;Register to save offset data for display A;Register +OFSTB;reg_offset_B;Register to save offset data for display B;Register +OG;reg_open_offset_G;Register to store OPEN offset data in G value;Register +OB;reg_open_offset_B;Register to store OPEN offset data in B value;Register +SR;reg_short_offset_R;Register to store SHORT offset data in R value;Register +SX;reg_short_offset_X;Register to store SHORT offset data in X value;Register +TYG;reg_0S_G_1;Register to to store 0S calibration data in G value;Register +TYB;reg_0S_B_1;Register to to store 0S calibration data in B value;Register +MYG;reg_0S_G_2;Register to to store 0S calibration data in G value;Register +MYB;reg_0S_B_2;Register to to store 0S calibration data in B value;Register +TZR;reg_0Ohm_R_1;Register to to store 0Ohm calibration data in R value;Register +TZX;reg_0Ohm_X_1;Register to to store 0Ohm calibration data in X value;Register +MZR;reg_0Ohm_R_2;Register to to store 0Ohm calibration data in R value;Register +MZX;reg_0Ohm_X_2;Register to to store 0Ohm calibration data in X value;Register +TSTDR;reg_std_R_1;Register to to store 50Ohm calibration data in R value;Register +TSTDX;reg_std_X_1;Register to to store 50Ohm calibration data in X value;Register +MSTDR;reg_std_R_2;Register to to store 50Ohm calibration data in R value;Register +MSTDX;reg_std_X_2;Register to to store 50Ohm calibration data in X value;Register +X;reg_sweep;Register to to store each point of sweep parameter;Register diff --git a/hp4194/control.py b/hp4194/control.py new file mode 100644 index 0000000000000000000000000000000000000000..e863cbf33f569727715e56c28b5647ee29fa755f --- /dev/null +++ b/hp4194/control.py @@ -0,0 +1,117 @@ +import pyvisa +import enum +import pandas as pd +import warnings +import numpy as np +import time + +class hp4194(object): + + def __init__(self,address="GPIB3::17::INSTR",library = "SCPI_command_summary.csv"): + self.adress = address + self.rm = pyvisa.ResourceManager() + self.inst = self.rm.open_resource(address) + self.inst.control_ren(5) # local lockout + self.inst.timeout = None + self.library = pd.read_csv(library,sep = ";") + + def __del__(self): + self.inst.control_ren(0) + self.inst.close() + + def __find_command(self,mnemonic): + rows_list = self.library.index[self.library["Mnemonic"]== mnemonic].tolist() + + if len(rows_list)==0: + raise Exception("Command not Found!") + + if len(rows_list)>1: + warnings.warn(f"{mnemonic} found at multiple commands with indexes:{rows_list}. Only the first appearance is considered valid!") + + row = rows_list[0] #first appearance + command =self.library.at[row,"Command"] + return command + + def write(self,mnemonic): + try: + command = self.__find_command(mnemonic) + except Exception as e: + print(e) + return + self.inst.write(command) + + def set_parameter(self,mnemonic,parameter): + try : + prefix = self.__find_command(mnemonic) + except Exception as e: + print(e) + return + + command = f"{prefix}={parameter}" + self.inst.write(command) + + def query(self,mnemonic): + try: + prefix = self.__find_command(mnemonic) + except Exception as e: + print(e) + return + + command = f"{prefix}?" + response = self.inst.query(command) + return response + + def read_register(self,mnemonic): + if mnemonic.startswith('reg')==False: + return + + string_response = self.query(mnemonic) + + if string_response == None: + return + + string_response = string_response.strip() # remove termination characters + values = string_response.split(",") + + for i in range(len(values)): + values[i]= float(values[i]) + + return values + + + def get_info(self,column_name,entry): + rows = self.library.loc[self.library[column_name] == entry] + with pd.option_context('display.max_rows', None, 'display.max_columns', None,'display.max_colwidth',3000): + display(rows) + + def __doc__(self): + with pd.option_context('display.max_rows', None, 'display.max_columns', None,'display.max_colwidth',3000): + display(self.library) + + + def __bit_set(self): + """ + Returns if the measurement has finished + """ + decimal=self.inst.read_stb() + status_byte_register= np.binary_repr(decimal,8) + measurement_bit = int(status_byte_register[-2]) + return bool(measurement_bit) + + def wait(self): + """ + Wait until the measurement is finished + """ + time.sleep(2) + while self.__bit_set()==False: + time.sleep(0.1) + + + + + + + + + + diff --git a/hp4194/cv.py b/hp4194/cv.py new file mode 100644 index 0000000000000000000000000000000000000000..6faec70a52eba27f18156411ae3499992e3ad88e --- /dev/null +++ b/hp4194/cv.py @@ -0,0 +1,454 @@ +import matplotlib +matplotlib.use('TkAgg',force = True) + +from interface import * +import control +from help import * +import time +from IPython.display import clear_output,display +import numpy as np +import datetime +import pandas as pd + +import matplotlib.pyplot as plt + +#connect to device +device = control.hp4194() +device.write('reset') +device.write('meas_imp') + +#create interface +sample,sample_dict = probendaten() +messparameter,messparameter_dict = messparameter() +sweep_parameter,sweep_parameter_dict = sweep_parameter() +control_panel,measure,view=control_panel() + +#set up interface +out = widgets.Output() +hbox1 = widgets.HBox([sample,control_panel]) +display(hbox1) +hbox2=widgets.HBox([messparameter,sweep_parameter]) +display(hbox2,out) + +#add widgets to a list for disabling them +all_widgets = [measure] +add_widgets_to_list(sample_dict,all_widgets) +add_widgets_to_list(sweep_parameter_dict,all_widgets) +add_widgets_to_list(messparameter_dict,all_widgets) + +def on_measure_clicked(b): + with out: + clear_output() + change_state(all_widgets) + if check_values(messparameter_dict,sweep_parameter_dict) == False: + information_box('Invalid Voltage Settings or Observation of non-existent data points!') + change_state(all_widgets) + return + + device.write('imp_G_B') + device.write('bias_off') + + device.write('sweep_freq') + device.set_parameter('set_start',sweep_parameter_dict['start'].value) + device.set_parameter('set_stop',sweep_parameter_dict['stop'].value) + device.set_parameter('set_nop',sweep_parameter_dict['nop'].value) + + if sweep_parameter_dict['type'].value=='Linear': + device.write('sweep_lin') + else:# log + device.write('sweep_log') + if sweep_parameter_dict['direction'].value=='Up': + device.write('sweep_up') + else: + device.write('sweep_down') + + device.write('sweep_single') + device.write('imp_monitor_I') + device.set_parameter('set_osc',sweep_parameter_dict['osc'].value) + device.set_parameter('set_delay_time',sweep_parameter_dict['d_time'].value) + device.set_parameter('set_delay_apperture',sweep_parameter_dict['d_apperture'].value) + device.set_parameter('aver_num',sweep_parameter_dict['averaging'].value) + device.write((sweep_parameter_dict["integration"].value).lower()) # Set integration number + + # Now that we have set the frequency values ask user for calibration + answer = ask_for_calibration() + if answer == True : #perform an open calibration + device.write('start_open_cal') + device.write('open_cal_on') #data saved in registers OG and OB + + + # open the file dialog + default_filename = f"{sample_dict['wafer'].value}_{sample_dict['sample'].value}_{sample_dict['field'].value}_CV.txt" + file = save_file(default_filename) + + #now perform the measurement + device.write('autoscale_A') # Autoscale A + device.write('autoscale_B') # Autoscale B + + # create the numpy list with the biases + # create the arrays with everything that needs to be saved into the array + f_values = [] + G_values = [] + B_values = [] + log_f_values = [] + omega_values = [] + log_omega_values = [] + Z_values = [] + phi_values = [] + D_values = [] + Cs_values =[] + Cp_values =[] + Cp_area_values =[] + Cs_area_values = [] + ReZ_values = [] + ImZ_values = [] + G_area_omega_values = [] + U_values = [] + area_values = [] + + + num_of_points =int(abs(messparameter_dict["stop"].value-messparameter_dict["start"].value)/abs(messparameter_dict["step"].value) + 1) + radius = messparameter_dict["radius"].value + area = np.pi * radius**2 # in um2 + area = area * 10**(-8) # in cm2 + biases= np.round(np.linspace(messparameter_dict["start"].value,messparameter_dict["stop"].value,num_of_points,endpoint = True),3) + + # frequency index + f_index = messparameter_dict['f_point'].value-1 + + # create the figure + fig = plt.figure(figsize=(12,10),layout = "constrained") + spec = fig.add_gridspec(ncols=3, nrows=2) + + ax1 = fig.add_subplot(spec[0,0]) + ax1_twin = ax1.twinx() + ax1.set_title("Cp/D(f) live") + ax1.set_xlabel("Frequency (Hz)") + ax1.set_ylabel("Cp (F)") + ax1_twin.set_ylabel("D") + + ax2 = fig.add_subplot(spec[0,1]) + ax2_twin = ax2.twinx() + ax2.set_title("Z/Phi(f) live") + ax2.set_xlabel("Frequency (Hz)") + ax2.set_ylabel("Z (Ohm)") + ax2_twin.set_ylabel("Phi (°)") + + ax3 = fig.add_subplot(spec[0,2]) + ax3.set_title("ImZ(ReZ(f)) live") + ax3.set_xlabel("Re Z (Ohm)") + ax3.set_ylabel("Im Z (Ohm)") + + ax4 = fig.add_subplot(spec[1,0]) + ax4_twin = ax4.twinx() + ax4.set_title("Cp/D(U)") + ax4.set_xlabel("Voltage U (V)") + ax4.set_ylabel("Cp (F)") + ax4_twin.set_ylabel("D") + + ax5 = fig.add_subplot(spec[1,1]) + ax5_twin = ax5.twinx() + ax5.set_title("Z/Phi(U)") + ax5.set_xlabel("Voltage U (V)") + ax5.set_ylabel("Z (Ohm)") + ax5_twin.set_ylabel("Phi (°)") + + ax6 = fig.add_subplot(spec[1,2]) + ax6_twin = ax6.twinx() + ax6.set_title("Cp/D(f)") + ax6.set_xlabel("Frequency (Hz)") + ax6.set_ylabel("Cp (F)") + ax6_twin.set_ylabel("D") + + """figManager = plt.get_current_fig_manager() + figManager.window.state('zoomed') + win = plt.gcf().canvas.manager.window + win.overrideredirect(1)""" + + view["v-point"].value =str(biases[messparameter_dict["v_point"].value-1]) + for i,bias in enumerate(biases): + view["v-value"].value = str(bias) + + # voltage index + v_index = messparameter_dict['v_point'].value-1 + + U_values.extend([bias]*sweep_parameter_dict['nop'].value) + area_values.extend([area]*sweep_parameter_dict['nop'].value) + device.set_parameter('set_bias', bias) #set the bias + device.write('start_sweep') #start the measurement + device.wait() #wait for completition + + # read the registers + + freq = np.array(device.read_register('reg_sweep')) + f_values.extend(freq) + G = np.array(device.read_register('reg_A')) + G_values.extend(G) + B = np.array(device.read_register('reg_B')) + B_values.extend(B) + + view["f-point"].value = str(freq[messparameter_dict["f_point"].value-1]) + time.sleep(messparameter_dict["sleep"].value) + + #do the calculations + log_f = np.log10(freq) + log_f_values.extend(log_f) + + omega = 2*np.pi*freq + omega_values.extend(omega) + + log_omega = np.log10(omega) + log_omega_values.extend(omega) + + Y_complex = G + 1j*B + Z_complex = 1/Y_complex + + Z = np.absolute(Z_complex) + Z_values.extend(Z) + phi = np.angle(Z_complex, deg = True) + phi_values.extend(phi) + + D = G/B + D_values.extend(D) + + Cp = B/omega + Cp_values.extend(Cp) + + Cs = Cp*(1+D**(2)) + Cs_values.extend(Cs) + + Cp_area = Cp/area + Cp_area_values.extend(Cp_area) + + Cs_area = Cs/area + Cs_area_values.extend(Cs_area) + + ReZ = np.real(Z_complex) + ImZ = np.imag(Z_complex) + ReZ_values.extend(ReZ) + ImZ_values.extend(ImZ) + + G_area_omega= G/area/omega + G_area_omega_values.extend(G_area_omega) + + # do the plots + # first the live ones + if i>0: + curve1.pop(0).remove() + curve1_twin.pop(0).remove() + curve2.pop(0).remove() + curve2_twin.pop(0).remove() + curve3.pop(0).remove() + + + + # frequency Cp/D plot + curve1 = ax1.plot(freq,Cp,color = 'b') + ax1.tick_params(axis = 'y',labelcolor = 'b') + + curve1_twin=ax1_twin.plot(freq,D, color = 'y') + ax1_twin.tick_params(axis='y',labelcolor = 'y') + + # frequecy Z-phi + curve2=ax2.plot(freq,Z,color = 'b') + ax2.tick_params(axis = 'y',labelcolor = 'b') + + curve2_twin = ax2_twin.plot(freq,phi, color = 'y') + ax2_twin.tick_params(axis='y',labelcolor = 'y') + + # Rez - Imz + curve3=ax3.plot(ReZ,ImZ,color = 'b') + ax3.tick_params(axis = 'y',labelcolor = 'b') + + # now the rest of the plots + # Voltage vs Cp D for the user specified frequency + # This is updated for every iteration + ax4.scatter(bias, Cp[f_index],color ='b') + ax4.tick_params(axis = 'y',labelcolor = 'b') + + ax4_twin.scatter(bias, D[f_index],color ='y') + ax4_twin.tick_params(axis = 'y',labelcolor = 'y') + + # Voltage, Z-phi + # This is also updated every iteration + ax5.scatter(bias, Z[f_index],color ='b') + ax4.tick_params(axis = 'y',labelcolor = 'b') + + ax5_twin.scatter(bias, phi[f_index],color ='y') + ax5_twin.tick_params(axis = 'y',labelcolor = 'y') + + # Final Plot + # This if for all the frequencies for the calculated voltage + + if biases[v_index]== bias: + ax6.scatter(freq,Cp,color = 'b') + ax6.tick_params(axis = 'y',labelcolor = 'b') + + ax6_twin.scatter(freq,D, color = 'y') + ax6_twin.tick_params(axis='y',labelcolor = 'y') + + wm = plt.get_current_fig_manager() + wm.window.state('zoomed') + win = plt.gcf().canvas.manager.window + win.overrideredirect(1) # draws a completely frameless window + + plt.pause(0.1) + + + if messparameter_dict["hysterisis"].value == True: + reversed_biases = reversed_array(biases) + for bias in reversed_biases: + clear_output(wait = True) + view["v-value"].value = str(bias) + + # voltage index + v_index = -messparameter_dict['v_point'].value # in reverse + U_values.extend([bias]*sweep_parameter_dict['nop'].value) + area_values.extend([area]*sweep_parameter_dict['nop'].value) + device.set_parameter('set_bias', bias) #set the bias + device.write('start_sweep') #start the measurement + device.wait() #wait for completition + + # read the registers + + freq = np.array(device.read_register('reg_sweep')) + f_values.extend(freq) + G = np.array(device.read_register('reg_A')) + G_values.extend(G) + B = np.array(device.read_register('reg_B')) + B_values.extend(B) + + + time.sleep(messparameter_dict["sleep"].value) + + #do the calculations + log_f = np.log10(freq) + log_f_values.extend(log_f) + + omega = 2*np.pi*freq + omega_values.extend(omega) + + log_omega = np.log10(omega) + log_omega_values.extend(omega) + + Y_complex = G + 1j*B + Z_complex = 1/Y_complex + + Z = np.absolute(Z_complex) + Z_values.extend(Z) + phi = np.angle(Z_complex, deg = True) + phi_values.extend(phi) + + D = G/B + D_values.extend(D) + + Cp = B/omega + Cp_values.extend(Cp) + + Cs = Cp*(1+D**(2)) + Cs_values.extend(Cs) + + Cp_area = Cp/area + Cp_area_values.extend(Cp_area) + + Cs_area = Cs/area + Cs_area_values.extend(Cs_area) + + ReZ = np.real(Z_complex) + ImZ = np.imag(Z_complex) + ReZ_values.extend(ReZ) + ImZ_values.extend(ImZ) + + G_area_omega= G/area/omega + G_area_omega_values.extend(G_area_omega) + + # do the plots + # first the live ones + + curve1.pop(0).remove() + curve1_twin.pop(0).remove() + curve2.pop(0).remove() + curve2_twin.pop(0).remove() + curve3.pop(0).remove() + + # frequency Cp/D plot + curve1=ax1.plot(freq,Cp,color = 'b') + ax1.tick_params(axis = 'y',labelcolor = 'b') + + curve1_twin = ax1_twin.plot(freq,D, color = 'y') + ax1_twin.tick_params(axis='y',labelcolor = 'y') + + # frequecy Z-phi + curve2=ax2.plot(freq,Z,color = 'b') + ax2.tick_params(axis = 'y',labelcolor = 'b') + + curve2_twin=ax2_twin.plot(freq,phi, color = 'y') + ax2_twin.tick_params(axis='y',labelcolor = 'y') + + # Rez - Imz + curve3=ax3.plot(ReZ,ImZ,color = 'b') + ax3.tick_params(axis = 'y',labelcolor = 'b') + + # now the rest of the plots + # Voltage vs Cp D for the user specified frequency + # This is updated for every iteration + ax4.scatter(bias, Cp[f_index],color ='b') + ax4.tick_params(axis = 'y',labelcolor = 'b') + + ax4_twin.scatter(bias, D[f_index],color ='y') + ax4_twin.tick_params(axis = 'y',labelcolor = 'y') + + # Voltage, Z-phi + # This is also updated every iteration + ax5.scatter(bias, Z[f_index],color ='b') + ax4.tick_params(axis = 'y',labelcolor = 'b') + + ax5_twin.scatter(bias, phi[f_index],color ='y') + ax5_twin.tick_params(axis = 'y',labelcolor = 'y') + + # Final Plot + # This if for all the frequencies for the calculated voltage + + if biases[v_index]== bias: + ax6.scatter(freq,Cp,color = 'b') + ax6.tick_params(axis = 'y',labelcolor = 'b') + + ax6_twin.scatter(freq,D, color = 'y') + ax6_twin.tick_params(axis='y',labelcolor = 'y') + wm = plt.get_current_fig_manager() + wm.window.state('zoomed') + + win = plt.gcf().canvas.manager.window + win.overrideredirect(1) # draws a completely frameless window + + plt.pause(0.1) + + win.overrideredirect(0) + + device.write('bias_off') + + # save to file + with open(file,'w') as f: + dt = datetime.datetime.now().replace(second=0, microsecond=0) + f.write(f'# Measurement started at {dt}'+"\n") + f.write(f"# Wafer {sample_dict['wafer'].value} Sample {sample_dict['sample'].value} Comment {sample_dict['comment'].value} Temperature {sample_dict['temperature'].value}" +"\n") + f.write(f"# V_start {messparameter_dict['start'].value} V V_stop {messparameter_dict['stop'].value} V V_step {messparameter_dict['step'].value} V"+"\n") + f.write(f"# f_start {sweep_parameter_dict['stop'].value} Hz f_stop {sweep_parameter_dict['stop'].value} Hz no_steps {sweep_parameter_dict['nop'].value} SweepType {sweep_parameter_dict['type'].value}"+"\n") + f.write(f"# OSC {sweep_parameter_dict['osc'].value} V"+"\n") + f.write(f"# integration time {sweep_parameter_dict['integration'].value} averaging {sweep_parameter_dict['averaging'].value}"+"\n") + f.write(f"# area {area} cm^2"+"\n") + f.write("\n") + + # create the dataframe + dictionary = {"U(V)": U_values, "A(cm^2)":area_values,"f(Hz)":f_values ,"log_f(Hz)":log_f_values,"omega(1/s)":omega_values,"log_omega(1/s)":log_omega_values,"Z(Ohm)":Z_values,"Phi(°)":phi_values, "G(S)":G_values,"B(S)":B_values,"D":D_values,"Cs(F)":Cs_values, "Cs_area(F/cm^2)":Cs_area_values,"Cp(F)":Cp_values,"Cp_area(F/cm^2)":Cp_area_values,"ReZ(Ohm)":ReZ_values,"ImZ(Ohm)":ImZ_values,"G_area/omega(S*s/cm^2)":G_area_omega_values} + + + df = pd.DataFrame(dictionary) + + #save the dictionary + df.to_csv(file,sep=" ",mode='a') + + information_box("measurement finished") + change_state(all_widgets) + +measure.on_click(on_measure_clicked) \ No newline at end of file diff --git a/hp4194/cv_interace.ipynb b/hp4194/cv_interace.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..4e7fbf553095cc4ea117003e9d2ef12b95c422a9 --- /dev/null +++ b/hp4194/cv_interace.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "912606ea-a3b6-43e8-94c5-8f1fe5281375", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5922ed122c8b4e82b4eae9959038b4bd", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(Tab(children=(GridspecLayout(children=(Label(value='Wafer', layout=Layout(grid_area='widget001'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "f803f463cf434773bfb596677188d79e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(Tab(children=(GridspecLayout(children=(Label(value='V_start (V)', layout=Layout(grid_area='widg…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9b25051b2f1a454ca1d7bdb39df52266", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%run cv.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff6b31d5-6708-452e-b919-56bd104365e1", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/hp4194/help.py b/hp4194/help.py new file mode 100644 index 0000000000000000000000000000000000000000..f90210da42bdbad06f49d3ea18177680695add05 --- /dev/null +++ b/hp4194/help.py @@ -0,0 +1,86 @@ +import ipywidgets as widgets +import tkinter as tk +from tkinter import filedialog +import tkinter.messagebox +import numpy as np + + +def add_widgets_to_list(source_dictionary,target_list): + for widget in source_dictionary.values(): + target_list.append(widget) + + +def change_state(widgets_list): + for widget in widgets_list: + widget.disabled = not widget.disabled + + +def ask_for_calibration(): + root = tk.Tk() + root.withdraw() + root.attributes("-topmost",True) + root.update() + answer=tk.messagebox.askyesno(message='Do you want to calibarate?') + + root.destroy() + return answer + +def save_file(default_filename): + root = tk.Tk() + root.withdraw() + root.lift() #show window above all other applications + + root.attributes("-topmost", True)#window stays above all other applications + + file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Txt files","*.txt")],title = "save results",initialfile =default_filename) + + while file.endswith(".txt") == False: + file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Txt files","*.txt")],title = "save results",initialfile =default_filename) + + root.destroy() + return file + +def information_box(information): + #open dialog and hide the main window + root = tk.Tk() + root.withdraw() + root.lift() #show window above all other applications + + root.attributes("-topmost", True)#window stays above all other applications + + #display meaagebox + tkinter.messagebox.showinfo(message=information) + root.destroy() + +def check_values(voltage:dict,freq:dict): + + if abs(voltage["step"].value) > abs(voltage["stop"].value-voltage["start"].value) or abs(voltage["step"].value)<0.01: + return False + + #Invert Polarity if nesaccary + if voltage["stop"].value > voltage["start"].value and voltage["step"].value < 0: + voltage["step"].value = -voltage["step"].value + elif voltage["stop"].value < voltage["start"].value and voltage["step"].value > 0: + voltage["step"].value = -voltage["step"].value + else: + pass + + # Now lets check for correct plots + + # calculate the number of points for voltage + voltage_points = abs(voltage["stop"].value-voltage["start"].value)/abs(voltage["step"].value) + 1 + + if voltage["v_point"].value > voltage_points: + return False + + # prove that we check a valld frequency point + if voltage["f_point"].value > freq['nop'].value: + return False + return True + +# create array for hysteris and remove the last element +def reversed_array(arr): + arr = list(arr) + arr.pop() + arr.reverse() + return np.array(arr) \ No newline at end of file diff --git a/hp4194/interface.py b/hp4194/interface.py new file mode 100644 index 0000000000000000000000000000000000000000..901c47372662e74b3dee16e8956c424b21176826 --- /dev/null +++ b/hp4194/interface.py @@ -0,0 +1,165 @@ +import ipywidgets as widgets +from ipywidgets import GridspecLayout,Layout, AppLayout,TwoByTwoLayout +import sys +from IPython.display import clear_output + + +def probendaten(): + width = 'auto' + probendaten = GridspecLayout(6,2) + + probendaten[0,0] = widgets.Label('Wafer',layout=Layout(height='auto', width = width)) + probendaten[0,1] = widgets.Label('Comment',layout=Layout(height='auto', width = width)) + probendaten[1,0] = widgets.Text(layout=Layout(height='auto', width = width)) # wafer value + probendaten[1,1] = widgets.Text(layout=Layout(height='auto', width = width)) # Bemerkung value + probendaten[2,0] = widgets.Label('Sample',layout=Layout(height='auto', width = width)) + probendaten[3,0] = widgets.Text(layout=Layout(height='auto', width = width)) #probe value + probendaten[4,0] = widgets.Label('Field',layout=Layout(height='auto', width = width)) + probendaten[4,1] = widgets.Label('Temeperature (K)',layout=Layout(height='auto', width = width)) + probendaten[5,0] = widgets.Text(layout=Layout(height='auto', width = width)) # Feld value + probendaten[5,1] = widgets.BoundedFloatText(value = 295,min = 0 ,max = sys.float_info.max,step = 1,layout=Layout(height='auto', width = width)) #Temperatur value + + dict = { + 'wafer': probendaten[1,0], + 'comment':probendaten[1,1], + 'sample':probendaten[3,0], + 'field':probendaten[5,0], + 'temperature':probendaten[5,1] + } + + tab = widgets.Tab() + tab.children = [probendaten] + tab.set_title(0,'Sample Information') + + return tab,dict + + +def messparameter(): + width = 'auto' + messparameter = GridspecLayout(15,1) + + messparameter[0,0] = widgets.Label('V_start (V)',layout=Layout(height='auto', width = width)) + messparameter[1,0] = widgets.BoundedFloatText(value = 1,min =-40 ,max = 40,step = 1,layout=Layout(height='auto', width = width)) # Start value + messparameter[2,0] = widgets.Label('V_stop (V)',layout=Layout(height='auto', width = width)) + messparameter[3,0] = widgets.BoundedFloatText(value = -3,min =-40 ,max = 40,step = 1,layout=Layout(height='auto', width = width)) #stop value + messparameter[4,0] = widgets.Label('V_step (V)',layout=Layout(height='auto', width = width)) + messparameter[5,0] = widgets.BoundedFloatText(value = 0.1,min = -80 ,max = 80,step = 0.01,layout=Layout(height='auto', width = width)) #step value + messparameter[6,0] = widgets.Label('Wait in Voltage Point (s)',layout=Layout(height='auto', width = width)) + messparameter[7,0] = widgets.BoundedFloatText(value = 0,min = 0 ,max = sys.float_info.max,step = 1,layout=Layout(height='auto', width = width)) #sleep value + messparameter[8,0] = widgets.Label('Radius of The Test Stucture(um)',layout=Layout(height='auto', width = width)) + messparameter[9,0] = widgets.BoundedIntText(value = 50,min = 1 ,max = sys.float_info.max,step = 1,layout=Layout(height='auto', width = width)) #radius value + messparameter[10,0] = widgets.Label('Observed Frequency Point',layout=Layout(height='auto', width = width)) + messparameter[11,0] = widgets.BoundedIntText(value = 2,min = 1 ,max = sys.maxsize,step = 1,layout=Layout(height='auto', width = width)) #Frequenzpunkt value + messparameter[12,0] = widgets.Label('Observed Voltage Point',layout=Layout(height='auto', width = width)) + messparameter[13,0] = widgets.BoundedIntText(value = 20,min = 1 ,max = sys.maxsize,step = 1,layout=Layout(height='auto', width = width)) #Spannungspunkt value + messparameter[14,0] = widgets.Checkbox(description = 'Hysterisis',value = True, indent = True, style = {'description_width': 'initial'},layout=Layout(height='auto', width = width)) #hysterisis value + + dict={ + 'start':messparameter[1,0], + 'stop':messparameter[3,0], + 'step':messparameter[5,0], + 'sleep':messparameter[7,0], + 'radius':messparameter[9,0], + 'f_point':messparameter[11,0], + 'v_point':messparameter[13,0], + 'hysterisis':messparameter[14,0] + } + + tab = widgets.Tab() + tab.children = [messparameter] + tab.set_title(0,'Voltage Parameters') + + + return tab,dict + +def sweep_parameter(): + width = 'auto' + + sweep_parameter= GridspecLayout(12,2) + + #title + + #first column + sweep_parameter[0,0] = widgets.Label('Number of Frequency Points',layout=Layout(height='auto', width = width)) + sweep_parameter[1,0] = widgets.BoundedIntText(value = 4,min =1 ,max = 401,step = 1,layout=Layout(height='auto', width = width)) # Anzahl Frequenzpunkte + sweep_parameter[2,0] = widgets.Label('f_start (Hz)',layout=Layout(height='auto', width = width)) + sweep_parameter[3,0] = widgets.BoundedFloatText(value=100000,min = 100, max = 40e6,step = 100,layout=Layout(height='auto', width = width)) #start frequency + sweep_parameter[4,0] = widgets.Label('f_stop (Hz)',layout=Layout(height='auto', width = width)) + sweep_parameter[5,0] = widgets.BoundedFloatText(value=1000000,min = 100, max = 40e6,step = 100,layout=Layout(height='auto', width = width)) #stop frequency + sweep_parameter[6,0] = widgets.Label('OSC Level (V)',layout=Layout(height='auto', width = width)) + sweep_parameter[7,0] = widgets.BoundedFloatText(value=0.05,min = 10e-3, max = 1,step = 1e-3,layout=Layout(height='auto', width = width)) # Osc level + sweep_parameter[8,0] = widgets.Label('Sweep Type',layout=Layout(height='auto', width = width)) + sweep_parameter[9,0] = widgets.RadioButtons(options = ['Logarithmic','Linear'],value = 'Linear',layout = Layout(height='auto', width = width)) #sweep type + sweep_parameter[10,0] = widgets.Label('Integration Time',layout=Layout(height='auto', width = width)) + sweep_parameter[11,0] = widgets.Dropdown(options = ['Short','Medium','Long'],value = 'Medium',layout = Layout(height='auto', width = width)) # Integration time + + #second column + sweep_parameter[0,1] = widgets.Label('Delay Time (ms)',layout=Layout(height='auto', width = width)) + sweep_parameter[1,1] = widgets.BoundedFloatText(value = 0,min =0 ,max = 3.6e6,step = 1,layout=Layout(height='auto', width = width)) # delay time + sweep_parameter[2,1] = widgets.Label('Delay Aperture (%)',layout=Layout(height='auto', width = width)) + sweep_parameter[3,1] = widgets.BoundedFloatText(value=0.5,min = 0.5, max = 100,step = 0.1,layout=Layout(height='auto', width = width)) #delay aperture + + # Now continue next to sweep type + sweep_parameter[8,1] = widgets.Label('Sweep Direction',layout=Layout(height='auto', width = width)) + sweep_parameter[9,1] = widgets.RadioButtons(options = ['Up','Down'],value = 'Up',layout = Layout(height='auto', width = width)) #sweep direction + sweep_parameter[10,1] = widgets.Label('Averaging Number',layout=Layout(height='auto', width = width)) + sweep_parameter[11,1] = widgets.FloatLogSlider(value=4,base=2,min=0,max=8, step=1,layout = Layout(height='auto', width = width))# Averaging + + dict = { + 'nop': sweep_parameter[1,0], + 'start': sweep_parameter[3,0], + 'stop': sweep_parameter[5,0], + 'osc': sweep_parameter[7,0], + 'type': sweep_parameter[9,0], + 'integration': sweep_parameter[11,0], + 'd_time': sweep_parameter[1,1], + 'd_apperture': sweep_parameter[3,1], + 'direction': sweep_parameter[9,1], + 'averaging': sweep_parameter[11,1] + } + tab = widgets.Tab() + tab.children = [sweep_parameter] + tab.set_title(0,'Sweep\nParameters') + + return tab,dict + + +def control_panel(): + width = 'auto' + control_panel = GridspecLayout(6,2) + + control_panel[0,:] = widgets.Button(description = "Start Measurement",layout=Layout(height='auto', width = width)) + control_panel[1,0] = widgets.Label("V-Point",layout=Layout(height='auto', width = width)) + control_panel[1,1] = widgets.Label("f-Point",layout=Layout(height='auto', width = width)) + + for j in range(2): + control_panel[2,j]= widgets.Text(disabled = True,layout=Layout(height='auto', width = width)) + + control_panel[3,0] = widgets.Label("Actual Voltage",layout=Layout(height='auto', width = width)) + + control_panel[4,0] = widgets.Text(disabled = True,layout=Layout(height='auto', width = width)) + + measure = control_panel[0,:] + + view = { + 'v-point': control_panel[2,0], + 'f-point': control_panel[2,1], + 'v-value':control_panel[4,0] + } + + return control_panel,measure,view + + + + + + + + + + + + + + + \ No newline at end of file