diff --git a/hp4155/ADU for double gate devices-test/double_gate_ADU.py b/hp4155/ADU for double gate devices-test/double_gate_ADU.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b66de872acefdc44a93bbdbfacf359d7c66e092
--- /dev/null
+++ b/hp4155/ADU for double gate devices-test/double_gate_ADU.py	
@@ -0,0 +1,597 @@
+import sys
+sys.path.insert(0, './lib')
+sys.path.insert(0, '..') #append parent directory
+
+
+from interface import *
+from help import *
+from measurements import *
+import configparser
+
+# Create the grids
+#create the information grid
+style = {'description_width': 'initial'}
+sample,smu_map = information_box_new()
+
+
+###end of sampling information#######################################
+
+# move checkboxes outside of the tabs
+transfer_check,integration_transfer,transfer_gates = header('Transfer Curve',"MEDium")
+output_check,integration_output,output_gates = header('Output Curve',"SHORt")
+gatediode_check,integration_gatediode,_=header('Gatediode',"MEDium")
+
+checkboxes = widgets.HBox([transfer_check,output_check,gatediode_check])
+display(checkboxes)
+
+#transfer
+Vds_transfer_widgets,Vds_transfer = secondary('VDS',0.05,0.95,1,1e-2)
+Vtg_transfer_widgets,Vtg_transfer = primary('VTG',-5,0.01,5,1e-3)
+Vbg_transfer_widgets,Vbg_transfer = synchronous('VBG',-15,0.1,15,1e-3)
+plot_transfer_widgets,plot_transfer = plot_config(1)
+transfer_box = widgets.VBox([integration_transfer,transfer_gates,Vds_transfer_widgets,Vtg_transfer_widgets,Vbg_transfer_widgets,plot_transfer_widgets])
+
+
+#output
+Vds_output_widgets,Vds_output = primary('VDS',0,0.01,5,1e-2)
+Vtg_output_widgets,Vtg_output = secondary('VTG',-5,2,5,1e-3)
+Vbg_output_widgets,Vbg_output = additional_secondary('VBG',-15,5,15,1e-3)
+plot_output_widgets,plot_output = plot_config(2)
+
+output_box = widgets.VBox([integration_output,output_gates,Vds_output_widgets,Vtg_output_widgets,Vbg_output_widgets,plot_output_widgets])
+#GateDiodde
+terminal = widgets.Dropdown(
+    options = ['VTG','VBG'],
+    description = 'Selected Gate:',
+    value ='VTG',
+    style=  {'description_width': 'initial'}
+)
+Vg_gatediode_widgets,Vg_gatediode=primary('VG',-5,0.05,5,1e-3)
+plot_gatediode_widgets,plot_gatediode = plot_config(3)
+gatediode_box = widgets.VBox([integration_gatediode,terminal,Vg_gatediode_widgets,plot_gatediode_widgets])
+
+#the tab widget
+children = [transfer_box,output_box,gatediode_box]
+titles = ["Transfer","Output","Gatediode"]
+tab = widgets.Tab()
+tab.children = children
+tab.titles = titles
+
+display(tab)
+
+button = widgets.Button(description ='Start Measurement')
+output = widgets.Output()
+
+export_ini_button = widgets.Button(description = 'Export as ini')
+import_ini_button = widgets.Button(description='Import from ini')
+
+all_widgets =[transfer_gates,output_gates,button,transfer_check,integration_transfer,output_check,integration_output,gatediode_check,integration_gatediode,terminal,export_ini_button,import_ini_button]
+
+add_widgets_to_list(sample,all_widgets)
+add_widgets_to_list(smu_map,all_widgets)
+add_widgets_to_list(Vds_transfer,all_widgets)
+add_widgets_to_list(Vtg_transfer,all_widgets)
+add_widgets_to_list(Vbg_transfer,all_widgets)
+add_widgets_to_list(Vds_output,all_widgets)
+add_widgets_to_list(Vtg_output,all_widgets)
+add_widgets_to_list(Vbg_output,all_widgets)
+add_widgets_to_list(Vg_gatediode,all_widgets)
+
+line = widgets.HBox([button,import_ini_button,export_ini_button])
+display(line,output)
+device = hp4155a.HP4155a('GPIB0::17::INSTR')
+
+def on_start_clicked(b):
+    with output:
+        clear_output()
+        #disable all widgets
+        disable_widgets(all_widgets)
+
+        #additional code to check smu configuration fast without modifing a lot of code
+        try:
+            check_configuration(smu_map)
+        except Exception as e:
+            error_box(e)
+            enable_widgets(all_widgets)
+            return
+
+        Setup(device) #setup the device
+
+        #for all measurements the same (copy the interface with values for parameter setting)
+        map = smu_map.copy()
+        for key,value in map.items():
+            map[key]= value.value
+
+        sample_copy = sample.copy()
+        for key,value in sample_copy.items():
+            sample_copy[key]=value.value
+
+        smu_s = device.smu_dict()
+        smu_s.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS') #Source smu is always grounded
+        
+        if transfer_check.value == True:
+            plot = plot_transfer.copy()
+            for key,value in plot.items():
+                plot[key] = value.value
+
+            points = number_of_points(Vds_transfer)
+
+            var2=device.var2_dict() #Vds_output is always used in tranfer curve with the same config
+            var2.update(
+                start=Vds_transfer['start'].value,
+                step=Vds_transfer['step'].value,
+                points=points,
+                comp=Vds_transfer['comp'].value,
+                pcomp=Vds_transfer['pcomp'].value,
+                stop = Vds_transfer['stop'].value #not important for setting VAR2 only parameters in file
+            )
+
+            # also drain smu is the same
+            smu_d = device.smu_dict()
+            smu_d.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2')
+            match transfer_gates.value:
+                case 'VTG' if check_values(Vtg_transfer,'primary') and check_values(Vds_transfer,'secondary'):
+                    smu_t = device.smu_dict()
+                    smu_t.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1')
+                    smu_b = device.smu_dict()
+                    smu_b.update(vname = 'VBG',iname='IBG',mode = 'COMM',func = 'CONS')
+                   
+                    var1 = device.var1_dict()
+                    var1.update(
+                        mode=Vtg_transfer['hyst'].value,
+                        start=Vtg_transfer['start'].value,
+                        stop=Vtg_transfer['stop'].value,
+                        step=Vtg_transfer['step'].value,
+                        comp =Vtg_transfer['comp'].value,
+                        pcomp=Vtg_transfer['pcomp'].value
+                    )
+                    #define the final dict
+                    meas_dict = {
+                        "SAMPLE":sample_copy,
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_D": smu_d,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "VAR2":var2,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_transfer.value,
+                    }
+                    #measure (later)
+                    Transfer_VTG(device,meas_dict)
+            
+                case 'VBG' if check_values(Vbg_transfer,'primary') and check_values(Vds_transfer,'secondary'):
+                    smu_t = device.smu_dict()
+                    smu_t.update(vname = 'VTG',iname='ITG',mode = 'COMM',func='CONS')
+                    smu_b = device.smu_dict()
+                    smu_b.update(vname = 'VBG',iname='IBG',mode = 'V',func = 'VAR1')
+
+                    var1 = device.var1_dict()
+                    var1.update(
+                        mode=Vbg_transfer['hyst'].value,
+                        start=Vbg_transfer['start'].value,
+                        stop=Vbg_transfer['stop'].value,
+                        step=Vbg_transfer['step'].value,
+                        comp =Vbg_transfer['comp'].value,
+                        pcomp=Vbg_transfer['pcomp'].value
+                    )
+
+                    #define the final dict
+                    meas_dict = {
+                        "SAMPLE":sample_copy,
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_D": smu_d,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "VAR2":var2,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_transfer.value,
+                    }
+                    #measure (later)
+                    Transfer_VBG(device,meas_dict)
+                  
+                    
+                case 'BOTH' if check_values(Vbg_transfer,'synchronous') and check_values(Vds_transfer,'secondary') and check_values(Vtg_transfer,'primary'):
+                    smu_t = device.smu_dict()
+                    smu_t.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1')  
+                    smu_b = device.smu_dict()
+                    smu_b.update(vname = 'VBG',iname='IBG',mode = 'V',func = 'VARD')
+
+                    var1 = device.var1_dict()
+                    var1.update(
+                        mode=Vtg_transfer['hyst'].value,
+                        start=Vtg_transfer['start'].value,
+                        stop=Vtg_transfer['stop'].value,
+                        step=Vtg_transfer['step'].value,
+                        comp =Vtg_transfer['comp'].value,
+                        pcomp=Vtg_transfer['pcomp'].value   
+                     )
+
+                    #calculate parameters for VARD
+                    ratio,offset = calculate_line(Vtg_transfer,Vbg_transfer)
+                    
+                    # update VBG step
+                    Vbg_transfer["step"].value = Decimal(str(ratio)) * Decimal(str(Vtg_transfer["step"].value))
+
+
+                    vard = device.vard_dict()
+                    vard.update(
+                        offset = offset,
+                        ratio = ratio,
+                        comp = Vbg_transfer["comp"].value,
+                        pcomp = Vbg_transfer["pcomp"].value,
+                        start = Vbg_transfer["start"].value,
+                        step = Vbg_transfer['step'].value,
+                        stop = Vbg_transfer['stop'].value,
+                    )
+
+                    #define the final dict
+                    meas_dict = {
+                        "SAMPLE":sample_copy,
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_D": smu_d,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "VAR2":var2,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_transfer.value,
+                        "VARD":vard
+                    }
+
+                    #measure (later)
+                    Transfer_BOTH(device,meas_dict)
+                case _ :
+                    information_box("Transfer Measurement skipped due to invalid parameters")
+            
+        if output_check.value == True:
+            smu_d = device.smu_dict()
+            smu_d.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR1')
+            
+            var1 = device.var1_dict()
+            var1.update(
+                mode=Vds_output['hyst'].value,
+                start=Vds_output['start'].value,
+                stop=Vds_output['stop'].value,
+                step=Vds_output['step'].value,
+                comp =Vds_output['comp'].value,
+                pcomp=Vds_output['pcomp'].value
+            )
+            
+            plot = plot_output.copy()
+            for key,value in plot.items():
+                plot[key] = value.value
+            
+            match output_gates.value:
+                case 'VTG' if check_values(Vds_output,'primary') and check_values(Vtg_output,'secondary'):
+                    smu_t=device.smu_dict()
+                    smu_t.update(vname ='VTG',iname = 'ITG',mode = 'V',func='VAR2')
+    
+                    smu_b= device.smu_dict()
+                    smu_b.update(vname='VBG',iname='IBG',mode = 'COMM',func='CONS')
+
+                    points = number_of_points(Vtg_output)
+
+                    var2=device.var2_dict()
+                    var2.update(
+                        start=Vtg_output['start'].value,
+                        step=Vtg_output['step'].value,
+                        points=points,
+                        comp=Vtg_output['comp'].value,
+                        pcomp=Vtg_output['pcomp'].value,
+                        stop = Vtg_output['stop'].value
+                    )
+
+                    meas_dict = {
+                        "SAMPLE":sample_copy,
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_D": smu_d,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "VAR2":var2,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_output.value,
+                    }
+
+                    #measure later
+                    Output_VTG(device,meas_dict)
+                    
+                case 'VBG' if check_values(Vds_output,'primary') and check_values(Vbg_output,'secondary'):
+                    smu_t=device.smu_dict()
+                    smu_t.update(vname ='VTG',iname = 'ITG',mode = 'COMM',func='CONS')
+                    
+                    smu_b= device.smu_dict()
+                    smu_b.update(vname='VBG',iname='IBG',mode = 'V',func = 'VAR2')
+
+                    points = number_of_points(Vbg_output)
+
+                    var2=device.var2_dict()
+                    var2.update(
+                        start=Vbg_output['start'].value,
+                        step=Vbg_output['step'].value,
+                        points=points,
+                        comp=Vbg_output['comp'].value,
+                        pcomp=Vbg_output['pcomp'].value,
+                        stop = Vbg_output['stop'].value
+                    )
+
+                    meas_dict = {
+                        "SAMPLE":sample_copy,
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_D": smu_d,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "VAR2":var2,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_output.value,
+                    }
+
+                    #measure later
+                    Output_VBG(device,meas_dict)
+
+                    
+                case 'BOTH' if check_values(Vds_output,'primary') and check_values(Vtg_output,'secondary') and check_values(Vbg_output,'secondary'):
+                    smu_t=device.smu_dict()
+                    smu_t.update(vname ='VTG',iname = 'ITG',mode = 'V',func='VAR2')
+                    
+                    smu_b= device.smu_dict()
+                    smu_b.update(vname='VBG',iname='IBG',mode = 'V',func = 'CONS')
+
+                    points = number_of_points(Vtg_output)
+
+                    var2=device.var2_dict()
+                    var2.update(
+                        start=Vtg_output['start'].value,
+                        step=Vtg_output['step'].value,
+                        points=points,
+                        comp=Vtg_output['comp'].value,
+                        pcomp=Vtg_output['pcomp'].value,
+                        stop = Vtg_output['stop'].value
+                    )
+
+                    points_VBG = number_of_points(Vbg_output)
+                    values_VBG = np.linspace(Vbg_output["start"].value,Vbg_output["stop"].value,num = points_VBG,endpoint= True)
+
+                    #there is not such unit we create it with a loop
+                    var3 = {
+                        "start":Vbg_output['start'].value,
+                        "step":Vbg_output['step'].value,
+                        "points":points_VBG,
+                        "comp":Vbg_output['comp'].value,
+                        "stop" : Vbg_output['stop'].value,
+                        "values" : values_VBG   
+                    }
+                    meas_dict = {
+                        "SAMPLE":sample_copy, 
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_D": smu_d,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "VAR2":var2,
+                        "VAR3":var3,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_output.value,
+                    }
+
+                    #measure later
+                    Output_BOTH(device,meas_dict)
+                    
+                case _ :
+                    information_box("Output Measurement skipped due to invalid parameters")
+                    
+
+        if gatediode_check.value == True:
+            #drain is disabled
+            device.smu_disable(map['D'])
+
+            # VAR1 is set with the same interface
+            var1 = device.var1_dict()
+            var1.update(
+                mode=Vg_gatediode['hyst'].value,
+                start=Vg_gatediode['start'].value,
+                stop=Vg_gatediode['stop'].value,
+                step=Vg_gatediode['step'].value,
+                comp =Vg_gatediode['comp'].value,
+                pcomp=Vg_gatediode['pcomp'].value
+            )
+            
+            plot = plot_gatediode.copy()
+            for key,value in plot.items():
+                plot[key] = value.value        
+                
+            match terminal.value:
+                case 'VTG' if check_values(Vg_gatediode,'primary'):
+                    smu_t=device.smu_dict()
+                    smu_t.update(vname ='VTG',iname = 'ITG',mode = 'V',func='VAR1')
+
+                    meas_dict = {
+                        "SAMPLE":sample_copy, 
+                        "MAP" : map,
+                        "SMU_T":smu_t,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_gatediode.value,
+                    }
+                    #measure later
+                    Gatediode_VTG(device,meas_dict)
+
+                case 'VBG' if check_values(Vg_gatediode,'primary'):
+                    smu_b=device.smu_dict()
+                    smu_b.update(vname ='VBG',iname = 'IBG',mode = 'V',func='VAR1')
+
+                    meas_dict = {
+                        "SAMPLE":sample_copy, 
+                        "MAP" : map,
+                        "SMU_B":smu_b,
+                        "SMU_S":smu_s,
+                        "VAR1":var1,
+                        "PLOT": plot, # plot in the tool
+                        "INTEGRATION": integration_gatediode.value,
+                    }
+                    #measure later
+                    Gatediode_VBG(device,meas_dict)
+                
+                case _ :
+                    information_box("Gatediode Measurement skipped due to invalid parameters")
+        
+        information_box("Measurement finished!")
+        enable_widgets(all_widgets)
+                      
+            
+def on_export_ini_clicked(b):
+    with output:
+        disable_widgets(all_widgets)
+        config = configparser.ConfigParser()
+        default_filename = 'ADU_double_gate.ini'
+        try:
+            file = save_as_ini(default_filename)
+            with open(file,'w') as configfile:
+                config.add_section('ALL VALUES ARE IN SI-UNITS!')
+                config.add_section('IT IS RECOMMENDED TO CHANGE THE INI FILE FROM THE INTERFACE AND DO NOT CHANGE ANY VALUES MANUALLY')
+    
+                # Transfer curve
+                config.add_section('Transfer')
+                config.set('Transfer','Integration',integration_transfer.value)
+    
+                config.add_section("Vtg_transfer")
+                for parameter,widget in Vtg_transfer.items():
+                    config.set('Vtg_transfer',parameter,str(widget.value))
+    
+                config.add_section("Vbg_transfer")
+                for parameter,widget in Vbg_transfer.items():
+                    config.set('Vbg_transfer',parameter,str(widget.value))
+    
+                config.add_section('Vds_transfer')
+                for parameter,widget in Vds_transfer.items():
+                    config.set('Vds_transfer',parameter,str(widget.value))
+
+                config.add_section('Plot_transfer')
+                for parameter,widget in plot_transfer.items():
+                    config.set('Plot_transfer',parameter,str(widget.value))
+    
+                #output
+                config.add_section('Output')
+                config.set('Output','Integration',integration_output.value)
+    
+                config.add_section("Vtg_output")
+                for parameter,widget in Vtg_output.items():
+                    config.set('Vtg_output',parameter,str(widget.value))
+    
+                config.add_section("Vbg_output")
+                for parameter,widget in Vbg_output.items():
+                    config.set('Vbg_output',parameter,str(widget.value))
+                
+                config.add_section('Vds_output')
+                for parameter,widget in Vds_output.items():
+                    config.set('Vds_output',parameter,str(widget.value))
+
+                config.add_section('Plot_output')
+                for parameter,widget in plot_output.items():
+                    config.set('Plot_output',parameter,str(widget.value))
+
+                # Gatediode
+                config.add_section('Gatediode')
+                config.set('Gatediode','Integration',integration_gatediode.value)
+    
+                config.add_section("Vg_gatediode")
+                for parameter,widget in Vg_gatediode.items():
+                    config.set('Vg_gatediode',parameter,str(widget.value)) 
+
+                config.add_section('Plot_gatediode')
+                for parameter,widget in plot_gatediode.items():
+                    config.set('Plot_gatediode',parameter,str(widget.value))
+    
+                config.write(configfile)
+        except Exception as e:
+            information_box(e)
+        
+        enable_widgets(all_widgets)
+
+
+def on_import_ini_clicked(b):
+    with output:
+        disable_widgets(all_widgets)
+        #load values to the interface
+        config = configparser.ConfigParser()
+        try:
+            file = load_ini()
+        except Exception as e:
+            information_box(e)
+            enable_widgets(all_widgets)
+            return
+
+        try:    
+            #read the values from each section
+            config.read(file)
+    
+            #transfer curve
+            integration_transfer.value = config.get('Transfer', "integration")
+            for parameter,widget in Vtg_transfer.items():
+                widget.value = config.get('Vtg_transfer',parameter)
+            for parameter,widget in Vds_transfer.items():
+                widget.value = config.get('Vds_transfer',parameter)
+            for parameter,widget in Vbg_transfer.items():
+                widget.value = config.get('Vbg_transfer',parameter)
+            for parameter,widget in plot_transfer.items():
+                widget.value = config.get('Plot_transfer',parameter)
+            
+            #output curve
+            integration_output.value = config.get('Output','integration')
+            for parameter,widget in Vtg_output.items():
+                widget.value = config.get('Vtg_output',parameter)
+            for parameter,widget in Vds_output.items():
+                widget.value = config.get('Vds_output',parameter)
+            for parameter,widget in Vbg_output.items():
+                widget.value = config.get('Vbg_output',parameter)
+    
+            for parameter,widget in plot_output.items():
+                widget.value = config.get('Plot_output',parameter)
+        
+            # gatediode
+            integration_gatediode.value = config.get('Gatediode','integration')
+            for parameter,widget in Vg_gatediode.items():
+                widget.value = config.get('Vg_gatediode',parameter)
+    
+            for parameter,widget in plot_gatediode.items():
+                widget.value = config.get('Plot_gatediode',parameter)
+    
+            information_box("all parameters loaded succesfully")
+        except Exception as error:
+            if type(error).__name__ =='NoSectionError':
+                information_box(f"{error}.Explanation: Section(header) [section] does not exist. Create a new ini file or compare it with functional ini files!")
+            elif type(error).__name__=='NoOptionError':
+                information_box(f'{error}.Explanation: The variable name before the equal sign is not recognized. Create a new ini file or compare it with functional ini files!')
+            elif type(error).__name__ == 'TraitError':
+                information_box(f'{error}.Explanation: Invalid Parameter Setting. Check if you set an invalid value!')
+            elif type(error).__name__ =="DuplicateOptionError":
+                information_box(f"{error}. Explaination: The section contains the setted parameter more than once!")
+            else:
+                information_box(f"A {type(error).__name__} has occurred. Create A new ini file")
+        enable_widgets(all_widgets)
+
+            
+button.on_click(on_start_clicked)
+import_ini_button.on_click(on_import_ini_clicked)
+export_ini_button.on_click(on_export_ini_clicked)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hp4155/ADU for double gate devices-test/double_gate_ADU_interface.ipynb b/hp4155/ADU for double gate devices-test/double_gate_ADU_interface.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..cecc7c917d748fd81e29c5cc2b8906c2a2e6cb33
--- /dev/null
+++ b/hp4155/ADU for double gate devices-test/double_gate_ADU_interface.ipynb	
@@ -0,0 +1,114 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "51b012d0-95b0-41c2-81bb-2205f3c53be2",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "e555573e22c546a6a305096c9d476115",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "HBox(children=(VBox(children=(Label(value='Sample Information', layout=Layout(height='auto', width='50%'), sty…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "d1459686805d4489854221f8fd6a9718",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "HBox(children=(Checkbox(value=True, description='Transfer Curve', indent=False), Checkbox(value=True, descript…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "4c7ddbf240104c3bab678fccc26db0df",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Tab(children=(VBox(children=(Dropdown(description='Integration Time', index=1, layout=Layout(height='auto', wi…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "57fedee09ea547dcb6ebaae046057df3",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "HBox(children=(Button(description='Start Measurement', style=ButtonStyle()), Button(description='Import from i…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "0e81c985ca234bc3bde9f042ae86921a",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%run double_gate_ADU.py"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "40d5f341-bc61-4698-8bdd-f99e94f4e325",
+   "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.11.4"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/hp4155/ADU for double gate devices-test/lib/help.py b/hp4155/ADU for double gate devices-test/lib/help.py
new file mode 100644
index 0000000000000000000000000000000000000000..265b43fd3a81f8a615c5ae8fdabb20102dbe1227
--- /dev/null
+++ b/hp4155/ADU for double gate devices-test/lib/help.py	
@@ -0,0 +1,303 @@
+import matplotlib.pyplot as plt
+import numpy as np
+import time
+from datetime import datetime
+
+import tkinter as tk
+from tkinter import filedialog
+import tkinter.messagebox
+import copy
+
+import pandas as pd
+
+#Get dataframe from results
+def get_dataframe_from_results(dictionary):
+    # creating a shallow copy
+    dictionary_copy = copy.copy(dictionary)
+    for old_key in dictionary_copy.keys():
+        if old_key[0]=='I':
+            new_key = old_key+"/A"
+        else: #V
+            new_key = old_key + "/V"
+        dictionary[new_key] = dictionary.pop(old_key)
+   
+    df = pd.DataFrame(dictionary)
+    return df
+def number_of_points(dict):
+    try:
+        diff = dict['stop'].value - dict['start'].value
+        ratio = abs(diff/dict['step'].value)
+        points = int(ratio+1)
+    
+    except ZeroDivisionError:
+        points = 1
+
+    #the programm crashed because for secondary step we had no problem setting start = stop and then it was dividing by zero
+    
+    if points>128:
+        points = 128
+    return points
+
+def check_values(dictionary,function):
+    valid = True
+
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    if function =='primary':
+        if abs(dictionary['step'].value) > abs(dictionary['stop'].value-dictionary['start'].value) or dictionary['step'].value==0:#invalid parameter setting 
+            valid = False
+            tkinter.messagebox.showerror(message="Invalid parameter setting!")
+
+        if dictionary['start'].value<dictionary['step'].value and dictionary['step'].value<0: #change polarity
+            dictionary['step'].value =(-1)*dictionary['step'].value
+
+        elif dictionary['start'].value>dictionary['stop'].value and dictionary['step'].value>0:
+            dictionary['step'].value = (-1)*dictionary['step'].value
+
+        else:
+            pass
+    
+    if function == 'secondary':
+        if dictionary['start'].value == dictionary['stop'].value:
+            pass
+        elif abs(dictionary['step'].value) > abs(dictionary['stop'].value-dictionary['start'].value) or dictionary['step'].value==0:#invalid parameter setting 
+            valid = False
+            tkinter.messagebox.showerror(message="Invalid parameter setting!")
+        if dictionary['start'].value<dictionary['step'].value and dictionary['step'].value<0: #change polarity
+            dictionary['step'].value =(-1)*dictionary['step'].value
+
+        elif dictionary['start'].value>dictionary['stop'].value and dictionary['step'].value>0:
+            dictionary['step'].value = (-1)*dictionary['step'].value
+
+    if function == 'synchronous':
+        pass
+    
+    if valid == True:
+        #check compliance
+        comp = dictionary['comp'].value
+        start = dictionary['start'].value
+        stop = dictionary['stop'].value
+
+        if abs(comp)*max(abs(start),abs(stop))>2:
+            dictionary["comp"].value=np.sign(comp)*2/max(abs(start),abs(stop))
+        
+    root.destroy()
+    return valid 
+
+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 enable_widgets(widgets_list):
+    for widget in widgets_list:
+        widget.disabled = False
+
+def disable_widgets(widgets_list):
+    for widget in widgets_list:
+        widget.disabled = True
+
+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 error_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.showerror(message=information)
+    root.destroy()
+
+#normalization factor to is for both normalizations 10**6/width mA/mm = uA/um = 10**(-6)A/um (returned from the tool)
+def normalization_factor(width):
+    factor = 10**6/width
+    return factor
+
+
+def save_as_ini(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=".ini", filetypes=[("Ini files","*.ini")],title = "save as ini",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".ini") == False:
+        #open again filedialog with error message box
+        answer=tk.messagebox.askyesno(message='Do you want to cancel the ini file Save?')
+        if answer == True:
+            raise Exception("Ini File Operation aborted!")
+        else:
+            file = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("Ini files","*.ini")],title = "save as ini",initialfile =default_filename)
+    root.destroy()
+    return file
+
+def load_ini():
+    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.askopenfilename(filetypes=[("Ini files","*.ini")],title ='Select ini file')
+    while file.endswith(".ini") == False:
+        #open again filedialog with error message box
+        answer=tk.messagebox.askyesno(message='Do you want to cancel the ini file load?')
+        if answer == True:
+            raise Exception("Ini File Operation aborted!")
+        else:
+            file = filedialog.askopenfilename(filetypes=[("Ini files","*.ini")],title = "Select ini file")
+    root.destroy()
+    return file
+
+# function to return ratio and offset for synchronous sweep measurement
+def calculate_line(VTG,VBG):
+    ratio = (VBG['stop'].value-VBG['start'].value)/(VTG['stop'].value-VTG['start'].value)
+    offset = VBG['start'].value-ratio*VTG['start'].value    
+    return ratio,offset
+
+
+
+#check if smu configuration has a double value
+def check_configuration(smu_map:dict):
+    #convert the dictionaries values to a list
+    
+    map_list = []
+    for element in smu_map.values():
+        map_list.append(element.value)
+
+    #remove the duplicates by using a set
+    map_set = set(map_list)
+
+    if len(map_set)!= len(map_list): #we have duplicates
+        raise Exception("You cannot assign a smu to multiple contacts")
+
+
+
+# The function for graph in the tool
+def graph_tool(params,device):
+    device.delete_axis("X")
+    device.delete_axis("Y1")
+    device.delete_axis("Y2")
+    device.del_user_functions()
+
+    device.clear_error_stack()
+
+    # How to define user functions correctly and not multiple times
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    plot_set= set(plot_list)
+
+    
+    #define the no values
+    for element in plot_set:
+        if element != "None":
+            if element.endswith("mm"): #only I values
+                #define the respective user function
+                device.user_function(element,"mA/mm",f"{element[:-2]}*{normalization_factor(params['SAMPLE']['width'])}") #max 3
+    
+            #define the absolute(A to indicate absolute) always 3 (max 6!)
+            if element.startswith('I') and element.endswith('mm'):
+                device.user_function('A'+element,"mA/mm",f"ABS({element})")
+            elif element.startswith('I') and element.endswith('mm')== False: 
+                device.user_function('A'+element,"A",f"ABS({element})")  
+             
+
+    # Now send the parameters in the tool
+    device.display_variable('X',params["PLOT"]["x"])
+    device.error_occured()
+    device.axis_scale('X','LIN')
+    device.error_occured()
+    device.display_variable_min_max('X','MIN',params["PLOT"]["x_min"])
+    device.error_occured()
+    device.display_variable_min_max('X','MAX',params["PLOT"]["x_max"])
+    device.error_occured()
+
+
+    if params["PLOT"]["y1_scale"]=='LOG':
+        device.display_variable('Y1',"A"+params["PLOT"]["y1"])
+    else:
+        device.display_variable('Y1',params["PLOT"]["y1"])
+    device.error_occured()
+    device.axis_scale('Y1',params["PLOT"]["y1_scale"])
+    device.error_occured()
+    device.display_variable_min_max('Y1','MIN',params["PLOT"]["y1_min"])
+    device.error_occured()
+    device.display_variable_min_max('Y1','MAX',params["PLOT"]["y1_max"])
+    device.error_occured()
+
+    if params["PLOT"]["y2"]!= "None":
+        if params["PLOT"]["y2_scale"]=='LOG':
+            device.display_variable('Y2',"A"+params["PLOT"]["y2"])
+        else:
+            device.display_variable('Y2',params["PLOT"]["y2"])
+        device.error_occured()
+        device.axis_scale('Y2',params["PLOT"]["y2_scale"])
+        device.error_occured()
+        device.display_variable_min_max('Y2','MIN',params["PLOT"]["y2_min"])
+        device.display_variable_min_max('Y2','MAX',params["PLOT"]["y2_max"])
+        device.error_occured()
+
+
+
+#plot software functions
+def values_to_plot(params,device):
+    #plotted variables as they are named in the tool
+    #return the plotted data for easier configuration
+    plotted_variables = {'X':device.get_axis_variable('X'),'Y1': device.get_axis_variable('Y1')}
+
+    if params["PLOT"]["y2"]!= "None":
+        plotted_variables['Y2']= device.get_axis_variable('Y2')
+
+    plot_values ={}
+    for axis,variable in plotted_variables.items():
+        plot_values.setdefault(axis,np.array(device.return_values(variable)))
+
+    return plot_values
+
+def set_axes_labels(plot_list):
+    axes_labels=[]
+    
+    # define the axes labels similarly to the user functions
+    for element in plot_list:
+        if element != "None": #only the last one
+            if element.startswith("V"):
+                label = f"{element} (V)"
+            elif element.startswith('I') and element.endswith('mm'):
+                label = f"{element[:-2]} (uA/um)"
+            else: # regular I
+                 label = f"{element} (A)"
+            axes_labels.append(label)
+    
+    return axes_labels
+
+    
+    
+
+    
+
+    
+
+   
\ No newline at end of file
diff --git a/hp4155/ADU for double gate devices-test/lib/interface.py b/hp4155/ADU for double gate devices-test/lib/interface.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cdca3cd6da686ea4d9610a4b9dbc7a29fb6ff86
--- /dev/null
+++ b/hp4155/ADU for double gate devices-test/lib/interface.py	
@@ -0,0 +1,340 @@
+import ipywidgets as widgets
+from ipywidgets import GridspecLayout,Layout
+from IPython.display import clear_output
+import sys
+import os
+
+width = "50%"
+height = 'auto'
+style = {'description_width': 'initial'}
+floatbox_width = "80%"
+
+def header(name,integration):
+    style = {'description_width': 'initial'}
+    options_integration=["SHORt","MEDium","LONG"]
+
+    check=widgets.Checkbox(
+        description = name,
+        value = True,
+        indent = False
+    )
+    integration= widgets.Dropdown(
+        options=options_integration,
+        value=integration,description='Integration Time',
+        style =style,
+        layout=Layout(height='auto', width="30%")
+    )
+
+    select =widgets.Dropdown(
+        options = ['VTG','VBG',"BOTH"],
+        description = 'Sweeping Gates:',
+        value ='BOTH',
+        style=  {'description_width': 'initial'}
+    )
+    
+    return check, integration ,select
+
+
+def primary(name,start,step,stop,comp):
+    primary_grid = GridspecLayout(4,4)
+    primary_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto'))
+    primary_grid[:,3].style.font_weight = 'bold'
+
+
+    #first line
+    primary_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto'))
+    primary_grid[0,1]=widgets.Label("Step(V)",layout=Layout(height='auto', width='auto'))
+    primary_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto'))
+
+    #second line
+    primary_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+    primary_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width))
+    primary_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+
+    #third line 
+    primary_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto'))
+    primary_grid[2,1] =widgets.Label("Power Compliance(W)(0=OFF)",layout=Layout(height='auto', width='auto'))#mind the gap
+    primary_grid[2,2] =widgets.Label("Hysterisis",layout=Layout(height='auto', width='auto'))#mind the gap
+
+    #fourth line
+    primary_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width))
+    primary_grid[3,1]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap
+    primary_grid[3,2]=widgets.Dropdown(options=['SINGle','DOUBle'],value='SINGle',layout=Layout(height='auto', width=floatbox_width))#mind the gap
+
+
+    parameters = {
+        'start': primary_grid[1,0],
+        'step': primary_grid[1,1],
+        'stop': primary_grid[1,2],
+        'comp': primary_grid[3,0],
+        'hyst':primary_grid[3,2],
+        'pcomp':primary_grid[3,1]
+    }
+    return primary_grid,parameters
+
+def secondary(name,start,step,stop,comp):
+    secondary_grid = GridspecLayout(4,4)
+    secondary_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto'))
+    secondary_grid[:,3].style.font_weight = 'bold'
+
+    #first line
+    secondary_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto'))
+    secondary_grid[0,1]=widgets.Label("Step(V)",layout=Layout(height='auto', width='auto'))
+    secondary_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto'))
+
+    #second line
+    secondary_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+    secondary_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width))
+    secondary_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+
+    #third line 
+    secondary_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto'))
+    secondary_grid[2,2] =widgets.Label("Power Compliance(W)(0=OFF)",layout=Layout(height='auto', width='auto'))#mind the gap
+
+    #fourth line
+    secondary_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width))
+    secondary_grid[3,2]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap
+
+    parameters = {
+        'start': secondary_grid[1,0],
+        'step': secondary_grid[1,1],
+        'stop':secondary_grid[1,2],
+        'comp':secondary_grid[3,0],
+        'pcomp':secondary_grid[3,2]
+    }
+    
+
+    return secondary_grid,parameters
+
+
+def information_box_new():
+    width = '90%'
+    sample_information=widgets.Label("Sample Information",layout=Layout(height=height, width='50%'))
+    sample_information.style.font_weight='bold'
+    information_grid=GridspecLayout(3,2)
+    
+    for i in range(3):
+        for j in range(2):
+            if i ==2 and j == 1:
+                information_grid[i,j]=widgets.Checkbox(value = True,indent = False)
+            elif i == 2 and j == 0:                
+                information_grid[i,j]=widgets.BoundedFloatText(
+                    value=100,
+                    min=1e-3,
+                    max=sys.float_info.max,step=1,
+                    layout=Layout(height=height, width=width)
+                )
+            else:
+                information_grid[i,j]=widgets.Text(layout=Layout(height=height, width=width))
+
+    information_grid[0,0].description = "Processing-Nr:"
+    information_grid[1,0].description = "Sample:"
+    information_grid[2,0].description = "Device Width(um):"
+    information_grid[0,1].description = "Field(XYY):"
+    information_grid[1,1].description = "Device:"
+    information_grid[2,1].description ='Save Plots'
+
+    for i in range(3):
+        for j in range(2):
+            information_grid[i,j].style = style
+
+    
+
+    config = widgets.Label("SMU Configuration",layout=Layout(height='auto', width='auto'))
+
+    top_gate = widgets.Dropdown(options=[1,2,3,4],value=1,layout=Layout(height='auto', width='auto'),description = 'Top Gate:',style = style)
+    drain = widgets.Dropdown(options=[1,2,3,4],value=2,layout=Layout(height='auto', width='auto'),description = 'Drain:',style = style)
+    back_gate = widgets.Dropdown(options=[1,2,3,4],value=3,layout=Layout(height='auto', width='auto'),description = 'Back Gate:',style = style)
+    source = widgets.Dropdown(options=[1,2,3,4],value=4,layout=Layout(height='auto', width='auto'),description = 'Source(Ground):',style = style)
+
+
+    vbox2 = widgets.VBox([config,top_gate,drain,back_gate,source])
+    vbox1=widgets.VBox([sample_information,information_grid])
+    display(widgets.HBox([vbox1,vbox2]))
+
+    information = {
+        'processing_number': information_grid[0,0],
+        'sample' : information_grid[1,0],
+        'field': information_grid[0,1],
+        'device':information_grid[1,1],    
+        'width': information_grid[2,0],
+        'save_fig':information_grid[2,1]
+    }
+    
+    smu_assign ={
+        'TG':top_gate,
+        'D':drain,
+        'S':source,
+        'BG':back_gate
+    }
+    
+    return information,smu_assign
+        
+def synchronous(name,start,step,stop,comp):
+    synchronous_grid = GridspecLayout(4,4)
+    synchronous_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto'))
+    synchronous_grid[:,3].style.font_weight = 'bold'
+
+
+    #first line
+    synchronous_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto'))
+    synchronous_grid[0,1]=widgets.Label("Step(V)(Only 1 Gate)",layout=Layout(height='auto', width='auto'),style = style)
+    synchronous_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto'))
+
+    #second line
+    synchronous_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+    synchronous_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width))
+    synchronous_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+
+    #third line 
+    synchronous_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto'))
+    synchronous_grid[2,1] =widgets.Label("Power Compliance(W)(0=OFF)",layout=Layout(height='auto', width='auto'),style = style)#mind the gap
+    synchronous_grid[2,2] =widgets.Label("Hysterisis(Only 1 gate)",layout=Layout(height='auto', width='auto'),style = style)#mind the gap
+
+    #fourth line
+    synchronous_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width))
+    synchronous_grid[3,1]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap
+    synchronous_grid[3,2]=widgets.Dropdown(options=['SINGle','DOUBle'],value='SINGle',layout=Layout(height='auto', width=floatbox_width))#mind the gap
+
+
+    parameters = {
+        'start': synchronous_grid[1,0],
+        'stop': synchronous_grid[1,2],
+        'comp': synchronous_grid[3,0],
+        'pcomp':synchronous_grid[3,1],
+        'step': synchronous_grid[1,1],
+        'hyst': synchronous_grid[3,2]
+    }
+    return synchronous_grid,parameters
+
+def additional_secondary(name,start,step,stop,comp):
+    secondary_grid = GridspecLayout(4,4)
+    secondary_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto'))
+    secondary_grid[:,3].style.font_weight = 'bold'
+
+    #first line
+    secondary_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto'))
+    secondary_grid[0,1]=widgets.Label("Step(V)",layout=Layout(height='auto', width='auto'))
+    secondary_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto'))
+
+    #second line
+    secondary_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+    secondary_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width))
+    secondary_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width))
+
+    #third line 
+    secondary_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto'))
+    secondary_grid[2,2] =widgets.Label("Power Compliance(W)(0=OFF)(Only 1 Gate)",layout=Layout(height='auto', width='auto'),style = style)#mind the gap
+
+    #fourth line
+    secondary_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width))
+    secondary_grid[3,2]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap
+
+    parameters = {
+        'start': secondary_grid[1,0],
+        'step': secondary_grid[1,1],
+        'stop':secondary_grid[1,2],
+        'comp':secondary_grid[3,0],
+        'pcomp':secondary_grid[3,2]
+    }
+    return secondary_grid,parameters
+
+
+def plot_config(meas): #meas = 1,2,3 for transfer,output,gatediode 
+    config_grid = GridspecLayout(6,4)
+
+    if meas== 3:
+        options_x= ['VTG','VBG']
+    else :
+        options_x = ['VTG','VBG','VDS']
+    
+    if meas ==3:
+        options = ['ITG','IBG','ITGmm','IBGmm','None']
+    else:
+        options = ['ITG','IBG','ID','ITGmm','IBGmm','IDmm','None']
+
+    # define the default values (y2 is always empty) taken from the interface
+    if meas == 1:# Transfer
+        x_name = 'VTG'
+        x_scale = 'LIN'
+        x_min = -5
+        x_max = 5
+        y1_name = 'IDmm'
+        y1_scale = 'LOG'
+        y1_min = 0
+        y1_max = 100
+    
+    elif meas == 2: # outptut
+        x_name = 'VDS'
+        x_scale = 'LIN'
+        x_min = 0
+        x_max = 5
+        y1_name = 'IDmm'
+        y1_scale = 'LIN'
+        y1_min = -100
+        y1_max = 100
+
+    else: # == 3 gatediode
+        x_name = 'VTG'
+        x_scale = 'LIN'
+        x_min = -5
+        x_max = 5
+        y1_name = 'ITGmm'
+        y1_scale = 'LOG'
+        y1_min = 0
+        y1_max = 10
+
+    
+    config_grid[0,:]=widgets.Label('Send Plotting configurations to the tool',layout=Layout(height='auto', width='auto'))
+    #first line headers
+    config_grid[1,1]= widgets.Label('X',layout=Layout(height='auto', width='auto'))
+    config_grid[1,2]= widgets.Label('Y1',layout=Layout(height='auto', width='auto'))
+    config_grid[1,3]= widgets.Label('Y2',layout=Layout(height='auto', width='auto'))
+
+    #first column 
+    config_grid[2,0] = widgets.Label('NAME',layout=Layout(height='auto', width='auto'))
+    config_grid[3,0] = widgets.Label('SCALE',layout=Layout(height='auto', width='auto'))
+    config_grid[4,0] = widgets.Label('MIN',layout=Layout(height='auto', width='auto'))
+    config_grid[5,0] = widgets.Label('MAX',layout=Layout(height='auto', width='auto'))
+
+    #iterate through the second line (NAME)
+    must_options = [x for x in options if x!='None']
+    config_grid[2,1]=widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_x,value = x_name)
+    config_grid[2,2]=widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = must_options,value = y1_name)
+    config_grid[2,3]=widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options,value = "None")
+
+    #Iterate through the third line (scale) 
+    options_scale = ['LIN','LOG']
+    config_grid[3,1] = widgets.Dropdown(value = x_scale,options = options_scale, layout=Layout(height='auto', width='auto'),disabled = True)
+    config_grid[3,2] = widgets.Dropdown(value = y1_scale,options = options_scale, layout=Layout(height='auto', width='auto'))
+    config_grid[3,3] = widgets.Dropdown(value = 'LIN',options = options_scale, layout=Layout(height='auto', width='auto'))
+
+    #iterate throuh the last 2 lines(min-max)
+   
+    config_grid[4,1] = widgets.FloatText(value = x_min,layout=Layout(height='auto', width='auto')) #min
+    config_grid[4,2] = widgets.FloatText(value = y1_min,layout=Layout(height='auto', width='auto')) #min
+    config_grid[4,3] = widgets.FloatText(value = 0,layout=Layout(height='auto', width='auto')) #min
+
+    config_grid[5,1]=widgets.FloatText(value = x_max,layout=Layout(height='auto', width='auto')) #max X-axis
+    config_grid[5,2]=widgets.FloatText(value = y1_max,layout=Layout(height='auto', width='auto')) #max Y1-axis
+    config_grid[5,3]=widgets.FloatText(value = 0,layout=Layout(height='auto', width='auto')) #max Y2-axis
+
+    config_dict = {
+        "x":config_grid[2,1],
+        "y1":config_grid[2,2],
+        "y2":config_grid[2,3],
+        #"x_scale":config_grid[3,1],
+        "y1_scale":config_grid[3,2],
+        "y2_scale":config_grid[3,3],
+        "x_min":config_grid[4,1],
+        "y1_min":config_grid[4,2],
+        "y2_min":config_grid[4,3],
+        "x_max":config_grid[5,1],
+        "y1_max":config_grid[5,2],
+        "y2_max":config_grid[5,3],
+    }
+
+    return config_grid,config_dict
+    
+
+    
\ No newline at end of file
diff --git a/hp4155/ADU for double gate devices-test/lib/measurements.py b/hp4155/ADU for double gate devices-test/lib/measurements.py
new file mode 100644
index 0000000000000000000000000000000000000000..8550c619fc2402889a4e26229e7e28ecf249587a
--- /dev/null
+++ b/hp4155/ADU for double gate devices-test/lib/measurements.py	
@@ -0,0 +1,1229 @@
+# New measurements file for ADU
+
+# The new measurements will have the smus configuration as a parameter and written from the interface
+
+import sys
+sys.path.insert(0, '..') #append parent directory
+
+import hp4155a
+from help import *
+from decimal import Decimal
+
+import os
+
+def Setup(device):
+    device.reset()
+
+    #setup sweep measurement mode
+    device.measurement_mode('SWE')
+
+    #disable all irrelevant units
+    device.disable_not_smu()
+
+# Transfer only VTG 
+def Transfer_VTG(device,params):
+    # calculate normalization factor
+    
+    norm = normalization_factor(params["SAMPLE"]["width"])
+    points = params["VAR2"]["points"]
+    try:
+        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
+        device.setup_smu(params["MAP"]['D'],params["SMU_D"])
+        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+    
+        device.setup_var1(params["VAR1"])
+        device.setup_var2(params["VAR2"])
+    
+        device.integration_time(params["INTEGRATION"])
+    
+        variables_list =["VTG","ITG","VDS","ID"]
+        device.variables_to_save(variables_list)
+    
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+    
+        device.single_measurement()
+        while device.operation_completed()==False:
+            pass
+    
+        device.autoscaling()
+        device.error_occured()
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+    # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_TOP_GATE_U.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Transfer Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gate:VTG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VTG from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        f.write(f"VDS from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        
+        if params['VAR1']['pcomp']==0:
+            f.write(f"Top Gate Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+            f.write(f"Top Gate Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+
+        if params['VAR2']['pcomp'] == 0:
+            f.write(f"Drain Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    plot_values = values_to_plot(params,device)
+
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels = set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = np.split(plot_values['X'],points)
+    y1 = np.split(plot_values['Y1'],points)
+    labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels
+    
+    for i in range(points):
+        ax1.plot(x[i],y1[i],label = f"VDS:{round(labels[i],3)} (V)")
+    
+    # Adding title
+    fig.suptitle('Transfer Curve', fontweight ="bold")
+    fig.legend(loc='outside right upper')
+
+    display(fig)
+    #save plot if checked
+    if params["SAMPLE"]['save_fig'] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+    
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = np.split(plot_values['Y2'],points)
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+
+        ax2.set_xlabel(axes_labels[0])
+         
+        ax2.set_ylabel(axes_labels[2])
+        for i in range(points):
+            ax2.plot(x[i],y2[i],label = f"VDS:{round(labels[i],3)} (V)")
+        
+        # Adding title
+        fig.suptitle('Transfer Curve', fontweight ="bold")
+        fig.legend(loc='outside right upper')
+    
+        display(fig)
+        #save plot if checked
+        if params["SAMPLE"]['save_fig'] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'_Y2.png')
+
+
+# Transfer only VBG
+def Transfer_VBG(device,params):
+    try:
+        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
+        device.setup_smu(params["MAP"]['D'],params["SMU_D"])
+        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+      
+    
+        device.setup_var1(params["VAR1"])
+        device.setup_var2(params["VAR2"])
+    
+        device.integration_time(params["INTEGRATION"])
+       
+    
+        variables_list =["VBG","IBG","VDS","ID"]
+        device.variables_to_save(variables_list)
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+        device.single_measurement()
+        while device.operation_completed()==False:
+            pass
+        device.autoscaling()
+        device.error_occured()
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    
+    except Exception as e:
+        error_box(e)
+        return
+    # calculate normalization factor
+    norm = normalization_factor(params["SAMPLE"]["width"])
+    points = params["VAR2"]["points"]
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+     # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_BACK_GATE_U.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Transfer Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gate:VBG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VBG from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        f.write(f"VDS from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        
+        #calculate the values
+        if params['VAR1']['pcomp']==0:
+            f.write(f"Back Gate Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+            f.write(f"Back Gate Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+            
+        if params['VAR2']['pcomp'] == 0:
+            f.write(f"Drain Current Compliance/A:{params['VAR2']['comp']}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{params['VAR2']['pcomp']}"+"\n")
+        
+    
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+         
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    plot_values = values_to_plot(params,device)
+
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels = set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = np.split(plot_values['X'],points)
+    y1 = np.split(plot_values['Y1'],points)
+    labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels
+    
+    for i in range(points):
+        ax1.plot(x[i],y1[i],label = f"VDS:{round(labels[i],3)} (V)")
+    
+    # Adding title
+    fig.suptitle('Transfer Curve', fontweight ="bold")
+    fig.legend(loc='outside right upper')
+
+    display(fig)
+    #save plot if checked
+    if params["SAMPLE"]['save_fig'] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+    
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = np.split(plot_values['Y2'],points)
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+
+        ax2.set_xlabel(axes_labels[0])
+         
+        ax2.set_ylabel(axes_labels[2])
+        for i in range(points):
+            ax2.plot(x[i],y2[i],label = f"VDS:{round(labels[i],3)} (V)")
+        
+        # Adding title
+        fig.suptitle('Transfer Curve', fontweight ="bold")
+        fig.legend(loc='outside right upper')
+    
+        display(fig)
+        #save plot if checked
+        if params["SAMPLE"]['save_fig'] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'_Y2.png')
+
+    
+def Transfer_BOTH(device,params):
+    try:
+        smu_t = device.smu_dict()
+        smu_t.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1')
+       
+        smu_b = device.smu_dict()
+        smu_b.update(vname = 'VBG',iname='IBG',mode = 'V',func = 'VARD')
+    
+        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
+        device.setup_smu(params["MAP"]['D'],params["SMU_D"])
+        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+      
+    
+        device.setup_var1(params["VAR1"])
+        device.setup_var2(params["VAR2"])
+        device.setup_vard(params["VARD"])
+    
+        device.integration_time(params["INTEGRATION"])
+    
+        variables_list =["VBG","IBG","VDS","ID","VTG","ITG"]
+        device.variables_to_save(variables_list)
+    
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+    
+        device.single_measurement()
+        while device.operation_completed()==False:
+            pass
+    
+        device.autoscaling()
+        device.error_occured()
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # calculate normalization factor
+    norm = normalization_factor(params["SAMPLE"]["width"])
+    points = params["VAR2"]["points"]
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+
+    # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_BOTH_GATES_U.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+    
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Transfer Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gates:VBG,VTG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VBG from {params['VARD']['start']}V to {params['VARD']['stop']}V with step {params['VARD']['step']}V"+"\n")
+        f.write(f"VTG from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        f.write(f"VDS from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        
+        #calculate thes
+        if params['VARD']['pcomp']==0:
+            f.write(f"Back Gate Current Compliance/A:{params['VARD']['comp']}"+"\n")
+        else:
+            f.write(f"Back Gate Power Compliance/A:{params['VARD']['pcomp']}"+"\n")
+
+        if params['VAR1']['pcomp']==0:
+            f.write(f"Top Gate Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+            f.write(f"Top Gate Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+
+        if params['VAR2']['pcomp'] == 0:
+            f.write(f"Drain Current Compliance/A:{params['VAR2']['comp']}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{params['VAR2']['pcomp']}"+"\n")
+
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+         
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+    plot_values = values_to_plot(params,device)
+
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels = set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = np.split(plot_values['X'],points)
+    y1 = np.split(plot_values['Y1'],points)
+    labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels
+    
+    for i in range(points):
+        ax1.plot(x[i],y1[i],label = f"VDS:{round(labels[i],3)} (V)")
+    
+    # Adding title
+    fig.suptitle('Transfer Curve', fontweight ="bold")
+    fig.legend(loc='outside right upper')
+
+    display(fig)
+    #save plot if checked
+    if params["SAMPLE"]['save_fig'] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+    
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = np.split(plot_values['Y2'],points)
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+
+        ax2.set_xlabel(axes_labels[0])
+         
+        ax2.set_ylabel(axes_labels[2])
+        for i in range(points):
+            ax2.plot(x[i],y2[i],label = f"VDS:{round(labels[i],3)} (V)")
+        
+        # Adding title
+        fig.suptitle('Transfer Curve', fontweight ="bold")
+        fig.legend(loc='outside right upper')
+    
+        display(fig)
+        #save plot if checked
+        if params["SAMPLE"]['save_fig'] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'Y2.png')
+
+# Output with VTG
+def Output_VTG(device,params):
+    try:
+        device.setup_smu(params['MAP']['TG'],params["SMU_T"])
+        device.setup_smu(params['MAP']['D'],params["SMU_D"])
+        device.setup_smu(params['MAP']['BG'],params["SMU_B"])
+        device.setup_smu(params['MAP']['S'],params["SMU_S"])
+        
+        device.setup_var1(params["VAR1"])
+        device.setup_var2(params["VAR2"])
+    
+        device.integration_time(params["INTEGRATION"])
+    
+        variables_list = ['VDS','ID','VTG','ITG']
+        device.variables_to_save(variables_list)
+    
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+        device.single_measurement()
+        
+        while device.operation_completed()==False:
+            pass
+    
+        device.autoscaling()
+        device.error_occured()
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    
+    # plot results
+    # calculate normalization factor
+    norm = normalization_factor(params['SAMPLE']["width"])
+    points = params["VAR2"]["points"]
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+    # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_TOP_GATE_A.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Output Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gate:VTG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VTG from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        f.write(f"VDS from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        
+        #calculate the values
+        if params['VAR2']['pcomp']==0:
+            f.write(f"Top Gate Current Compliance/A:{params['VAR2']['comp']}"+"\n")
+        else:
+            f.write(f"Top Gate Power Compliance/A:{params['VAR2']['pcomp']}"+"\n")
+
+        if params['VAR1']['pcomp'] == 0:
+            f.write(f"Drain Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+         
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    plot_values = values_to_plot(params,device)
+
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels = set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = np.split(plot_values['X'],points)
+    y1 = np.split(plot_values['Y1'],points)
+    labels =np.mean(np.array_split(df["VTG/V"],points),axis = 1) # VDS values for labels
+    
+    for i in range(points):
+        ax1.plot(x[i],y1[i],label = f"VTG:{round(labels[i],3)} (V)")
+    
+    # Adding title
+    fig.suptitle('Output Curve', fontweight ="bold")
+    fig.legend(loc='outside right upper')
+
+    display(fig)
+    #save plot if checked
+    if params["SAMPLE"]['save_fig'] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+    
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = np.split(plot_values['Y2'],points)
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+
+        ax2.set_xlabel(axes_labels[0])
+         
+        ax2.set_ylabel(axes_labels[2])
+        for i in range(points):
+            ax2.plot(x[i],y2[i],label = f"VTG:{round(labels[i],3)} (V)")
+        
+        # Adding title
+        fig.suptitle('Output Curve', fontweight ="bold")
+        fig.legend(loc='outside right upper')
+    
+        display(fig)
+        #save plot if checked
+        if params["SAMPLE"]['save_fig'] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'Y2.png')
+    
+
+#Output VBG
+def Output_VBG(device,params):
+    try:
+        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
+        device.setup_smu(params["MAP"]['D'],params["SMU_D"])
+        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+    
+    
+        device.setup_var1(params["VAR1"])
+        device.setup_var2(params["VAR2"])
+    
+        device.integration_time(params["INTEGRATION"])
+    
+        variables_list = ['VDS','ID','VBG','IBG']
+        device.variables_to_save(variables_list)
+         
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+    
+        device.single_measurement()
+        
+        while device.operation_completed()==False:
+            pass
+        
+        device.autoscaling()
+        device.error_occured()
+        
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # plot results
+
+    # calculate normalization factor
+    norm = normalization_factor(params["SAMPLE"]["width"])
+    points = params["VAR2"]["points"]
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+    # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_BACK_GATE_A.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Output Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gate:VBG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VBG from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        f.write(f"VDS from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        
+        #calculate the values
+        if params['VAR2']['pcomp']==0:
+            f.write(f"Back Gate Current Compliance/A:{params['VAR2']['comp']}"+"\n")
+        else:
+            f.write(f"Back Gate Power Compliance/A:{params['VAR2']['pcomp']}"+"\n")
+
+        if params['VAR1']['pcomp'] == 0:
+            f.write(f"Drain Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+         
+        f.write("\nResults\n")
+
+
+    plot_values = values_to_plot(params,device)
+
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels = set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = np.split(plot_values['X'],points)
+    y1 = np.split(plot_values['Y1'],points)
+    labels =np.mean(np.array_split(df["VBG/V"],points),axis = 1) # VDS values for labels
+    
+    for i in range(points):
+        ax1.plot(x[i],y1[i],label = f"VBG:{round(labels[i],3)} (V)")
+    
+    # Adding title
+    fig.suptitle('Output Curve', fontweight ="bold")
+    fig.legend(loc='outside right upper')
+
+    display(fig)
+    #save plot if checked
+    if params["SAMPLE"]['save_fig'] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+    
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = np.split(plot_values['Y2'],points)
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+
+        ax2.set_xlabel(axes_labels[0])
+         
+        ax2.set_ylabel(axes_labels[2])
+        for i in range(points):
+            ax2.plot(x[i],y2[i],label = f"VBG:{round(labels[i],3)} (V)")
+        
+        # Adding title
+        fig.suptitle('Output Curve', fontweight ="bold")
+        fig.legend(loc='outside right upper')
+    
+        display(fig)
+        #save plot if checked
+        if params["SAMPLE"]['save_fig'] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'Y2.png')
+    
+# Output both
+def Output_BOTH(device,params):
+    try:
+        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
+        device.setup_smu(params["MAP"]['D'],params["SMU_D"])
+        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+    
+    
+        device.setup_var1(params["VAR1"])
+        device.setup_var2(params["VAR2"])
+        
+    
+        device.integration_time(params["INTEGRATION"])
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+        
+    
+        variables_list = ['VDS','ID','VBG','IBG','VTG','ITG']
+        device.variables_to_save(variables_list)
+    
+        for i , value in enumerate(params["VAR3"]['values']):
+            cons = device.cons_smu_dict()
+            cons.update(comp = params['VAR3']['comp'],value = value)
+            device.setup_cons_smu(params['MAP']['BG'],cons)
+    
+            if i == 0:
+                device.single_measurement()
+            else:
+                device.append_measurement()
+        
+            while device.operation_completed()==False:
+                pass
+            device.autoscaling()
+            device.error_occured()
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # plot results
+    points = params["VAR2"]['points']*params["VAR3"]["points"] # number of curves
+
+    # calculate normalization factor
+    norm = normalization_factor(params["SAMPLE"]["width"])
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+      # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_BOTH_GATES_A.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Output Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gates:VBG,VTG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VBG from {params['VAR3']['start']}V to {params['VAR3']['stop']}V with step {params['VAR3']['step']}V"+"\n")
+        f.write(f"VTG from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        f.write(f"VDS from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+      
+        
+        #calculate the values
+        f.write(f"Back Gate Current Compliance/A:{params['VAR3']['comp']}"+"\n")
+        
+        if params['VAR2']['pcomp']==0:
+            f.write(f"Top Gate Current Compliance/A:{params['VAR2']['comp']}"+"\n")
+        else:
+            f.write(f"Top Gate Power Compliance/A:{params['VAR2']['pcomp']}"+"\n")
+
+
+        if params['VAR1']['pcomp'] == 0:
+            f.write(f"Drain Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+         
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    plot_values = values_to_plot(params,device)
+
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels = set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = np.split(plot_values['X'],points)
+    y1 = np.split(plot_values['Y1'],points)
+    labels_VTG =np.mean(np.array_split(df["VTG/V"],points),axis = 1) # VTG values for labels
+    labels_VBG = np.mean(np.array_split(df["VBG/V"],points),axis = 1) # VBG values for labels
+    
+    for i in range(points):
+        ax1.plot(x[i],y1[i],label = f"VTG:{round(labels_VTG[i],3)} (V) , VBG:{round(labels_VBG[i],3)} (V)")
+    
+    # Adding title
+    fig.suptitle('Output Curve', fontweight ="bold")
+    fig.legend(loc='outside right upper')
+
+    display(fig)
+    #save plot if checked
+    if params["SAMPLE"]['save_fig'] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+    
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = np.split(plot_values['Y2'],points)
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+
+        ax2.set_xlabel(axes_labels[0])
+         
+        ax2.set_ylabel(axes_labels[2])
+        for i in range(points):
+            ax2.plot(x[i],y2[i],label = f"VTG:{round(labels_VTG[i],3)} (V) , VBG:{round(labels_VBG[i],3)} (V)")
+        
+        # Adding title
+        fig.suptitle('Output Curve', fontweight ="bold")
+        fig.legend(loc='outside right upper')
+    
+        display(fig)
+        #save plot if checked
+        if params["SAMPLE"]['save_fig'] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'_Y2.png')
+  
+
+def Gatediode_VTG(device,params):
+    try:
+        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
+        device.smu_disable(params["MAP"]['BG'])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+    
+        device.setup_var1(params["VAR1"])
+    
+        device.integration_time(params["INTEGRATION"])
+    
+        variables_list = ['VTG','ITG']
+        device.variables_to_save(variables_list)
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+    
+        device.single_measurement()
+        
+        while device.operation_completed()==False:
+            pass
+        device.autoscaling()
+        device.error_occured()
+        
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # calculate normalization factor
+    norm = normalization_factor(params['SAMPLE']["width"])
+
+    # Append the normalized current 
+    df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+     # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_TOP_GATE_D.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Gatediode Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gate:VTG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VTG from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        
+        #calculate the values
+        if params['VAR1']['pcomp']==0:
+            f.write(f"Top Gate Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+            f.write(f"Top Gate Power Compliance/A:{params['VAR1']['pcomp'].value}"+"\n")
+
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+        
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    plot_values = values_to_plot(params,device) 
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels =set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = plot_values['X']
+    y1 = plot_values['Y1']
+    
+    ax1.plot(x,y1)
+    fig.suptitle('Gatediode Curve', fontweight ="bold")
+    display(fig)
+
+    if params["SAMPLE"]["save_fig"] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+
+
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = plot_values['Y2']
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+        
+        ax2.set_xlabel(axes_labels[0])
+        ax2.set_ylabel(axes_labels[2])
+        ax2.plot(x,y2)
+
+        fig.suptitle('Gatediode Curve', fontweight ="bold")
+        display(fig)
+
+        if params["SAMPLE"]["save_fig"] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'_Y2.png')
+
+   
+def Gatediode_VBG(device,params):
+    try:
+        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
+        device.smu_disable(params["MAP"]['TG'])
+        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+    
+        device.setup_var1(params["VAR1"])
+    
+        device.integration_time(params["INTEGRATION"])
+    
+        variables_list = ['VBG','IBG']
+        device.variables_to_save(variables_list)
+         
+        try:
+            plotted_variables = graph_tool(params,device)
+        except Exception as e:
+            error_box(e)
+            return
+    
+    
+        device.single_measurement()
+        while device.operation_completed()==False:
+            pass
+    
+        device.autoscaling()
+        device.error_occured()
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # plot results
+
+    # calculate normalization factor
+    norm = normalization_factor(params["SAMPLE"]["width"])
+
+    # Append the normalized current 
+    df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+    # Save the results
+    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_BACK_GATE_D.txt"
+
+    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=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
+
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Gatediode Curve at {date}"+"\n")
+        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
+        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
+        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
+        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
+        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        f.write("Sweeping Gate:VBG"+"\n\n")
+
+        f.write('Parameters\n')
+        f.write(f"VBG from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
+        
+        #calculate the values
+        if params['VAR1']['pcomp']==0:
+            f.write(f"Back Gate Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        else:
+            f.write(f"Back Gate Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+
+        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+         
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    plot_values = values_to_plot(params,device) 
+    # Plot user specified results
+    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
+
+    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
+    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
+    axes_labels =set_axes_labels(plot_list)
+
+    if scale_list[1]=='LOG':
+        ax1.set_yscale('log')
+
+
+    #now set the labels
+    ax1.set_xlabel(axes_labels[0])
+    ax1.set_ylabel(axes_labels[1])
+
+    x = plot_values['X']
+    y1 = plot_values['Y1']
+    
+    ax1.plot(x,y1)
+    fig.suptitle('Gatediode Curve', fontweight ="bold")
+    display(fig)
+
+    if params["SAMPLE"]["save_fig"] == True:
+        filename= os.path.splitext(file)[0]
+        fig.savefig(filename+'_Y1.png')
+
+
+    #add the second axis if applicable
+    if plot_list[2]!= "None":
+        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+        y2 = plot_values['Y2']
+        
+        if scale_list[2]=='LOG':
+            ax2.set_yscale('log')
+        
+        ax2.set_xlabel(axes_labels[0])
+        ax2.set_ylabel(axes_labels[2])
+        ax2.plot(x,y2)
+
+        fig.suptitle('Gatediode Curve', fontweight ="bold")
+        display(fig)
+
+        if params["SAMPLE"]["save_fig"] == True:
+            filename= os.path.splitext(file)[0]
+            fig.savefig(filename+'_Y2.png')
\ No newline at end of file
diff --git a/hp4155/hp4155a.py b/hp4155/hp4155a.py
index b48a8e0a3629033bed373d2e7c455c41e14ef8ca..e6d32d16809b195bf4f3351501e7a277ed8239d1 100644
--- a/hp4155/hp4155a.py
+++ b/hp4155/hp4155a.py
@@ -43,9 +43,22 @@ class HP4155a(object):
     #go to stress page 
     def stress_page(self):
         self.inst.write(":PAGE:STR")
-    
+        
     def error(self):
-        return self.inst.query(":SYST:ERR?")
+        error = self.inst.query(":SYST:ERR?")
+        error_code = int(error.split(',',1)[0])
+        error_message = error.split(',',1)[1]
+        return error_code,error_message
+        
+    def error_occured(self):
+        code,message = self.error()
+        if code != 0:
+            raise Exception(message)
+
+    def clear_error_stack(self):
+        code,_ = self.error()
+        while code != 0:
+            code,_ = self.error() 
 
     def operation_completed(self):
         text = self.inst.query('*OPC?')
@@ -161,6 +174,11 @@ class HP4155a(object):
     def display_variable_min_max(self,axis,extremum,value):
         command = f":PAGE:DISP:GRAP:{axis}:{extremum} {value}"
         self.inst.write(command)
+
+    def get_axis_variable(self,axis):
+        command = f":PAGE:DISP:GRAP:{axis}:NAME?"
+        var_name = self.inst.query(command)
+        return var_name.rstrip() #remove \n
     
     def autoscaling(self):
         self.inst.write(":PAGE:GLIS:SCAL:AUTO ONCE")
@@ -186,6 +204,10 @@ class HP4155a(object):
         command = f":PAGE:DISP:MODE {mode}"
         self.inst.write(command)
 
+    def delete_axis(self,axis):
+        command = f":PAGE:DISP:GRAP:{axis}:DEL"
+        self.inst.write(command)
+
     
     #delete all user functions
     def del_user_functions(self):